Photonix

Card

A flexible container component for grouping related content and actions.

Preview

Basic Card
This is a standard elevated card

Cards contain content and actions about a single subject. They are surface containers that hold content and actions.

Usage
"use client";

import { Button, Card, CardBody, CardFooter, CardHeader, Text } from '@photonix/ultimate';
import { MoreHorizontalOutline } from '@photonix/icons';

export default function CardBasicExample() {
    return (
        <Card w={350} maxW="100%">
            <CardHeader
                title="Basic Card"
                subtitle="This is a standard elevated card"
                action={<Button variant="tertiary" leadingIcon={<MoreHorizontalOutline />} />}
            />
            <CardBody>
                <Text variant="body-md" color="secondary">
                    Cards contain content and actions about a single subject. They are surface containers that hold content and actions.
                </Text>
            </CardBody>
            <CardFooter>
                <Button variant="secondary">Cancel</Button>
                <Button>Submit</Button>
            </CardFooter>
        </Card>
    );
}

Component API

Card

Prop
Type
Default
Description
variant
CardVariant
'elevated'
Card variant style
orientation
"horizontal" | "vertical"
'vertical'
Card orientation
isHoverable
boolean
false
Whether the card is interactive (hover states)
isClickable
boolean
false
Whether the card is clickable (cursor pointer)
children
React.ReactNode
-
Children elements
p
ResponsiveValue<SpacingToken>
-
Padding on all sides
px
ResponsiveValue<SpacingToken>
-
Padding inline (left/right)
py
ResponsiveValue<SpacingToken>
-
Padding block (top/bottom)
pt
ResponsiveValue<SpacingToken>
-
Padding block start (top)
pb
ResponsiveValue<SpacingToken>
-
Padding block end (bottom)
pl
ResponsiveValue<SpacingToken>
-
Padding inline start (left)
pr
ResponsiveValue<SpacingToken>
-
Padding inline end (right)
m
ResponsiveValue<SpacingToken | "auto">
-
Margin on all sides
mx
ResponsiveValue<SpacingToken | "auto">
-
Margin inline (left/right)
my
ResponsiveValue<SpacingToken | "auto">
-
Margin block (top/bottom)
mt
ResponsiveValue<SpacingToken | "auto">
-
Margin block start (top)
mb
ResponsiveValue<SpacingToken | "auto">
-
Margin block end (bottom)
ml
ResponsiveValue<SpacingToken | "auto">
-
Margin inline start (left)
mr
ResponsiveValue<SpacingToken | "auto">
-
Margin inline end (right)
display
ResponsiveValue<DisplayValue>
-
CSS display property
aspectRatio
ResponsiveValue<string | number>
-
Aspect Ratio
flexDirection
ResponsiveValue<FlexDirection>
-
Flex direction
flexWrap
ResponsiveValue<boolean | FlexWrap>
-
Flex wrap behavior
flex
ResponsiveValue<string | number>
-
Shorthand for flex-grow, flex-shrink, flex-basis
flexGrow
ResponsiveValue<number>
-
Flex grow factor
flexShrink
ResponsiveValue<number>
-
Flex shrink factor
flexBasis
ResponsiveValue<string | number>
-
Flex basis
order
ResponsiveValue<number>
-
Order
gap
ResponsiveValue<SpacingToken>
-
Gap between items
columnGap
ResponsiveValue<SpacingToken>
-
Column gap
rowGap
ResponsiveValue<SpacingToken>
-
Row gap
alignItems
ResponsiveValue<AlignItems>
-
Align items (cross axis)
alignContent
ResponsiveValue<string>
-
Align content (multiline)
alignSelf
ResponsiveValue<AlignSelf>
-
Align self
justifyContent
ResponsiveValue<JustifyContent>
-
Justify content (main axis)
justifyItems
ResponsiveValue<string>
-
Justify items (grid)
placeItems
ResponsiveValue<string>
-
Place items (align-items + justify-items)
placeContent
ResponsiveValue<string>
-
Place content (align-content + justify-content)
bg
ResponsiveValue<BackgroundToken>
-
Background color using public background tokens mapped to canonical surface vars
pageBg
ResponsiveValue<PageBackgroundToken>
-
Page background using canonical background-* vars for page/root containers
borderRadius
ResponsiveValue<RadiusToken>
-
Border radius using border-radius-* tokens
shadow
ResponsiveValue<ShadowToken>
-
Box shadow using shadow-* tokens
opacity
ResponsiveValue<number>
-
Opacity
border
ResponsiveValue<string>
-
borderWidth
ResponsiveValue<number | BorderWidthToken>
-
borderStyle
ResponsiveValue<string>
-
borderColor
ResponsiveValue<string>
-
textAlign
ResponsiveValue<TextAlign>
-
fontSize
ResponsiveValue<string | number>
-
fontWeight
ResponsiveValue<string | number>
-
lineHeight
ResponsiveValue<string | number>
-
color
ResponsiveValue<string>
-
w
ResponsiveValue<string | number>
-
Width - accepts CSS value
h
ResponsiveValue<string | number>
-
Height - accepts CSS value
minW
ResponsiveValue<string | number>
-
Min width - accepts CSS value
minH
ResponsiveValue<string | number>
-
Min height - accepts CSS value
maxW
ResponsiveValue<string | number>
-
Max width - accepts CSS value
maxH
ResponsiveValue<string | number>
-
Max height - accepts CSS value
position
ResponsiveValue<Position>
-
CSS position property
top
ResponsiveValue<string | number>
-
Top position
right
ResponsiveValue<string | number>
-
Right position
bottom
ResponsiveValue<string | number>
-
Bottom position
left
ResponsiveValue<string | number>
-
Left position
inset
ResponsiveValue<string | number>
-
Inset shortcut
zIndex
ResponsiveValue<number>
-
Z-index
overflow
ResponsiveValue<Overflow>
-
CSS overflow property
overflowX
ResponsiveValue<Overflow>
-
CSS overflow-x property
overflowY
ResponsiveValue<Overflow>
-
CSS overflow-y property
cursor
ResponsiveValue<string>
-
pointerEvents
ResponsiveValue<string>
-
userSelect
ResponsiveValue<string>
-
transform
ResponsiveValue<string>
-
transition
ResponsiveValue<string>
-

CardHeader

Prop
Type
Default
Description
title
React.ReactNode
-
Card title
subtitle
React.ReactNode
-
Card subtitle
isVerified
boolean
-
Whether the entity is verified (shows a checkmark icon)
action
React.ReactNode
-
Action element (e.g., menu button)
avatar
React.ReactNode
-
Avatar or icon to display
children
React.ReactNode
-
Children elements

CardFooter

Prop
Type
Default
Description
justify
"center" | "start" | "end" | "between"
'end'
Justify content alignment
children
React.ReactNode
-
Children elements

CardImage

Prop
Type
Default
Description
position
"top" | "bottom" | "left" | "fill"
'top'
Image position
rounded
boolean
false
Whether to apply border radius to all corners

Variants

Visual Styles

Cards come in three main visual styles: elevated (default), outlined, and filled.

Elevated

Has shadow

Outlined

Has border

Filled

Has background

Visual Styles
"use client";

import { Card, CardBody, Flex, Text } from '@photonix/ultimate';

export default function CardVisualStylesExample() {
    return (
        <Flex gap="md" wrap="wrap">
            <Card variant="elevated" w={200}>
                <CardBody>
                    <Text variant="title-sm">Elevated</Text>
                    <Text variant="body-sm" color="secondary">Has shadow</Text>
                </CardBody>
            </Card>
            <Card variant="outlined" w={200}>
                <CardBody>
                    <Text variant="title-sm">Outlined</Text>
                    <Text variant="body-sm" color="secondary">Has border</Text>
                </CardBody>
            </Card>
            <Card variant="filled" w={200}>
                <CardBody>
                    <Text variant="title-sm">Filled</Text>
                    <Text variant="body-sm" color="secondary">Has background</Text>
                </CardBody>
            </Card>
        </Flex>
    );
}

Overlay

Use the overlay variant for cards with a background image. The card adapts text color for readability.

Architecture
Urban Architecture
Modern aesthetic for the urban explorer.
Light Demo
Nature Escape
Find peace in the quiet mountains.
Overlay
"use client";

import { Box, Button, Card, CardFooter, CardHeader, CardImage, Flex, HStack, IconButton, Text } from '@photonix/ultimate';
import { AddOutline, DownloadOutline, MoreVerticalOutline, UserOutline } from '@photonix/icons';

const LIGHT_IMAGE = '/card_nature.png';
const DARK_IMAGE = '/card_architecture.png';

export default function CardOverlayExample() {
    return (
        <Flex gap="md" wrap="wrap">
            <Box w={300}>
                <Card variant="overlay" h={400}>
                    <CardImage position="fill" src={DARK_IMAGE} alt="Architecture" />
                    <Box position="absolute" top={8} right={8} zIndex={2}>
                        <IconButton variant="tertiary" size="small" icon={<MoreVerticalOutline />} aria-label="More" />
                    </Box>
                    <div style={{ flex: 1 }} />
                    <CardHeader
                        title="Urban Architecture"
                        subtitle="Modern aesthetic for the urban explorer."
                    />
                    <CardFooter justify="between">
                        <HStack gap="sm">
                            <HStack gap="4xs" align="center">
                                <UserOutline size={24} />
                                <Text variant="title-md">1.2k</Text>
                            </HStack>
                        </HStack>
                        <Button size="small" variant="primary" leadingIcon={<AddOutline />}>Follow</Button>
                    </CardFooter>
                </Card>
            </Box>

            <Box w={300}>
                <Card variant="overlay" h={400}>
                    <CardImage position="fill" src={LIGHT_IMAGE} alt="Light Demo" />
                    <Box position="absolute" top={8} right={8} zIndex={2}>
                        <IconButton variant="tertiary" size="small" icon={<MoreVerticalOutline />} aria-label="More" />
                    </Box>
                    <div style={{ flex: 1 }} />
                    <CardHeader
                        title="Nature Escape"
                        subtitle="Find peace in the quiet mountains."
                    />
                    <CardFooter justify="between">
                        <HStack gap="sm">
                            <HStack gap="4xs" align="center">
                                <UserOutline size={24} />
                                <Text variant="title-md">320</Text>
                            </HStack>
                            <HStack gap="4xs" align="center">
                                <DownloadOutline size={24} />
                                <Text variant="title-md">26</Text>
                            </HStack>
                        </HStack>
                        <Button size="small" variant="primary" leadingIcon={<AddOutline />}>Follow</Button>
                    </CardFooter>
                </Card>
            </Box>
        </Flex>
    );
}

Interactive

Cards can be hoverable and clickable.

Hover me

I lift up on hover

Click me

I am clickable too

Interactive
"use client";

import { Card, CardBody, Flex, Text } from '@photonix/ultimate';

export default function CardInteractiveExample() {
    return (
        <Flex gap="md" wrap="wrap">
            <Card isHoverable w={200}>
                <CardBody>
                    <Text variant="title-sm">Hover me</Text>
                    <Text variant="body-sm" color="secondary">I lift up on hover</Text>
                </CardBody>
            </Card>
            <Card isHoverable isClickable w={200}>
                <CardBody>
                    <Text variant="title-sm">Click me</Text>
                    <Text variant="body-sm" color="secondary">I am clickable too</Text>
                </CardBody>
            </Card>
        </Flex>
    );
}

With Image (Padded)

Inset the image with small padding and rounded corners for a framed look.

Architecture
Modern Architecture
Clean lines and minimalist design.
With Image (Padded)
"use client";

import { Box, Button, Card, CardFooter, CardHeader, CardImage, HStack, Text } from '@photonix/ultimate';
import { UserOutline } from '@photonix/icons';

export default function CardWithImageExample() {
    return (
        <Box maxW={360}>
            <Card>
                <Box p="2xs" pb="none">
                    <CardImage
                        rounded
                        src="/card_architecture.png"
                        alt="Architecture"
                        style={{ aspectRatio: '16/9' }}
                    />
                </Box>
                <CardHeader
                    title="Modern Architecture"
                    isVerified
                    subtitle="Clean lines and minimalist design."
                />
                <CardFooter justify="between">
                    <HStack gap="sm">
                        <HStack gap="4xs" align="center">
                            <UserOutline size={24} />
                            <Text variant="title-md">1.2k</Text>
                        </HStack>
                    </HStack>
                    <Button size="small">Read More</Button>
                </CardFooter>
            </Card>
        </Box>
    );
}

Full Bleed Image

A card where the image covers the top area completely without any padding.

Nature
Mountain Serenity
Exploring the peaceful peaks.
Full Bleed Image
"use client";

import { Box, Button, Card, CardFooter, CardHeader, CardImage, HStack, Text } from '@photonix/ultimate';
import { UserOutline } from '@photonix/icons';

export default function CardFullBleedExample() {
    return (
        <Box maxW={360}>
            <Card>
                <CardImage src="/card_nature.png" alt="Nature" style={{ aspectRatio: '16/9' }} />
                <CardHeader
                    title="Mountain Serenity"
                    isVerified
                    subtitle="Exploring the peaceful peaks."
                />
                <CardFooter justify="between">
                    <HStack gap="sm">
                        <HStack gap="4xs" align="center">
                            <UserOutline size={24} />
                            <Text variant="title-md">842</Text>
                        </HStack>
                    </HStack>
                    <Button size="small" variant="primary">Explore</Button>
                </CardFooter>
            </Card>
        </Box>
    );
}

Social Post

Cards tailored for social feeds, featuring an avatar and multiple action buttons.

AW

Alexander Wright
2 hours ago - San Francisco

Just deployed the new Photonix design system update. The automatic brightness detection for overlay cards is a game changer for UX.

Architecture
Social Post
"use client";

import { Box, Button, Card, CardBody, CardFooter, CardHeader, CardImage, HStack, IconButton, Text } from '@photonix/ultimate';
import { MoreHorizontalOutline, MoreVerticalOutline } from '@photonix/icons';

const DARK_IMAGE = '/card_architecture.png';

export default function CardSocialPostExample() {
    return (
        <Box maxW={420}>
            <Card>
                <CardHeader
                    avatar={
                        <Box w={40} h={40} borderRadius="full" bg="brand-primary" display="flex" alignItems="center" justifyContent="center">
                            <Text variant="title-sm" style={{ color: 'var(--foreground-neutral-primary-inverse)' }}>AW</Text>
                        </Box>
                    }
                    title="Alexander Wright"
                    subtitle="2 hours ago - San Francisco"
                    action={<IconButton variant="tertiary" size="small" icon={<MoreHorizontalOutline />} aria-label="More options" />}
                />
                <CardBody>
                    <Text variant="body-lg">
                        Just deployed the new Photonix design system update. The automatic brightness detection for overlay cards is a game changer for UX.
                    </Text>
                </CardBody>
                <CardImage src={DARK_IMAGE} alt="Architecture" style={{ aspectRatio: '16/9' }} />
                <CardFooter justify="between">
                    <HStack gap="sm">
                        <Button variant="tertiary" size="small">Like</Button>
                        <Button variant="tertiary" size="small">Comment</Button>
                    </HStack>
                    <IconButton variant="tertiary" size="small" icon={<MoreVerticalOutline />} aria-label="Settings" />
                </CardFooter>
            </Card>
        </Box>
    );
}

Product Card

E-commerce style card with badges, ratings, and pricing displays.

Headphones

Electronics

SALE

Studio Headphones Gen 3

$299.00

$350.00

Product Card
"use client";

import { Box, Button, Card, CardBody, CardFooter, CardImage, HStack, Text, VStack } from '@photonix/ultimate';

export default function CardProductExample() {
    return (
        <Box maxW={300}>
            <Card isHoverable>
                <CardImage src="/card_architecture.png" alt="Headphones" style={{ aspectRatio: '1/1' }} />
                <CardBody>
                    <VStack gap="xs">
                        <HStack justify="between" align="center">
                            <Text variant="body-sm" color="secondary">Electronics</Text>
                            <Box p="4xs" px="md" borderRadius="full" bg="secondary">
                                <Text variant="label-sm">SALE</Text>
                            </Box>
                        </HStack>
                        <Text variant="title-lg">Studio Headphones Gen 3</Text>
                        <HStack gap="xs" align="center">
                            <Text variant="title-lg" color="brand">$299.00</Text>
                            <Text variant="body-sm" color="secondary" style={{ textDecoration: 'line-through' }}>$350.00</Text>
                        </HStack>
                    </VStack>
                </CardBody>
                <CardFooter>
                    <Button isFullWidth variant="primary">Add to Bag</Button>
                </CardFooter>
            </Card>
        </Box>
    );
}

Horizontal Layout

Cards can be laid out horizontally, which is ideal for lists and search results.

Demo
Full Bleed Horizontal
Ideal for blog post previews or search results where the image needs to be prominent.
Demo
Inset Rounded Image
Horizontal layout with a padded and rounded image container.
Horizontal Layout
"use client";

import { Box, Button, Card, CardFooter, CardHeader, CardImage, HStack, Text, VStack } from '@photonix/ultimate';
import { UserOutline } from '@photonix/icons';

const LIGHT_IMAGE = '/card_nature.png';

export default function CardHorizontalExample() {
    return (
        <VStack gap="md" w="100%">
            <Card orientation="horizontal" h={180} w="100%">
                <CardImage position="left" src={LIGHT_IMAGE} alt="Demo" style={{ width: 180 }} />
                <VStack flexGrow={1} flexShrink={1} flexBasis="0%" align="stretch" minW={0}>
                    <CardHeader
                        title="Full Bleed Horizontal"
                        subtitle="Ideal for blog post previews or search results where the image needs to be prominent."
                    />
                    <div style={{ flex: 1 }} />
                    <CardFooter justify="end">
                        <Button size="small" variant="secondary">Read Article</Button>
                    </CardFooter>
                </VStack>
            </Card>

            <Card orientation="horizontal" h={180} w="100%">
                <Box p="2xs" w={180} flexShrink={0}>
                    <CardImage
                        rounded
                        src={LIGHT_IMAGE}
                        alt="Demo"
                        style={{ width: '100%', height: '100%', objectFit: 'cover' }}
                    />
                </Box>
                <VStack flexGrow={1} flexShrink={1} flexBasis="0%" align="stretch" minW={0}>
                    <CardHeader
                        title="Inset Rounded Image"
                        subtitle="Horizontal layout with a padded and rounded image container."
                    />
                    <div style={{ flex: 1 }} />
                    <CardFooter justify="between">
                        <HStack gap="sm" align="center">
                            <UserOutline size={20} />
                            <Text variant="body-md">4.8</Text>
                        </HStack>
                        <Button size="small" variant="tertiary">Quick View</Button>
                    </CardFooter>
                </VStack>
            </Card>
        </VStack>
    );
}

On this page

Preview
Component API
Variants
Visual Styles
Overlay
Interactive
With Image
Full Bleed Image
Social Post
Product Card
Horizontal Layout
Photonix UI - React Components, Templates & Figma Design System