All components elevatedoutlinesubtlesolidsmmdlg
Card
Content containers with elevated, outline, subtle, and solid variants — Root resolves variant and size once and every part inherits them through context.
Project settings
Manage tokens and themes.
12345678910111213141516171819202122import { Card } from "#components/ui/ark-ui/card.tsx";import { Button } from "#components/ui/ark-ui/button.tsx";
export function Example() { return ( // variant/size resolve once on Root; every part inherits them via context <Card.Root variant="elevated" size="md"> <Card.Header> <Card.Title>Project settings</Card.Title> <Card.Description>Manage tokens and themes.</Card.Description> </Card.Header> <Card.Body>Rename the project or transfer ownership.</Card.Body> <Card.Footer> <Button variant="surface" size="sm">Cancel</Button> <Button variant="solid" size="sm">Save</Button> </Card.Footer> </Card.Root> );}
// composition works per part — e.g. render the title as a link:// <Card.Title asChild><a href="/settings">Project settings</a></Card.Title>Variants
Project settings
Manage tokens and themes.
Project settings
Manage tokens and themes.
Project settings
Manage tokens and themes.
Project settings
Manage tokens and themes.
Sizes
Project settings
Manage tokens and themes.
Project settings
Manage tokens and themes.
Project settings
Manage tokens and themes.
Install
1npx stylexblocks add cardSource
components/ui/ark-ui/card.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164import * as stylex from "@stylexjs/stylex";import { createSlotRecipeContext } from "#lib/ark-ui/create-slot-recipe-context.tsx";import { defineSlotRecipe } from "#lib/recipe-props.ts";import { colorPalette } from '@stylexblocks/ui/color-palette.stylex.ts'import { fontSizes } from '@stylexblocks/ui/tokens/font-sizes.stylex.ts'import { fontWeights } from '@stylexblocks/ui/tokens/font-weights.stylex.ts'import { semanticColors } from '@stylexblocks/ui/semantic-tokens/colors.stylex.ts'import { semanticRadii } from '@stylexblocks/ui/semantic-tokens/radii.stylex.ts'import { semanticShadows } from '@stylexblocks/ui/semantic-tokens/shadows.stylex.ts'import { spacing } from '@stylexblocks/ui/tokens/spacing.stylex.ts'
const cardRoot = stylex.create({ base: { display: 'flex', flexDirection: 'column', position: 'relative', minWidth: 0, wordWrap: 'break-word', borderRadius: semanticRadii.panel, '--card-radius': semanticRadii.panel, '--card-concentric-radius': 'max(0px, calc(var(--card-radius) - var(--card-padding)))', color: semanticColors.fg, textAlign: 'start', },})
const cardRootSizes = stylex.create({ sm: { '--card-padding': spacing._2_5, }, md: { '--card-padding': spacing._4, }, lg: { '--card-padding': spacing._6, },})
const cardRootVariants = stylex.create({ elevated: { backgroundColor: semanticColors.bgPanel, boxShadow: semanticShadows.md, borderWidth: '0.5px', borderColor: semanticColors.borderEmphasized, }, outline: { backgroundColor: semanticColors.bgPanel, borderWidth: '1px', borderColor: semanticColors.border, }, subtle: { backgroundColor: colorPalette.muted, }, solid: { backgroundColor: colorPalette.solid, color: colorPalette.contrast, },})
const cardTitle = stylex.create({ base: { fontWeight: fontWeights.medium, },})
const cardTitleSizes = stylex.create({ sm: { fontSize: fontSizes.sm, }, md: { fontSize: fontSizes.md, }, lg: { fontSize: fontSizes.lg, },})
const cardDescription = stylex.create({ base: { color: semanticColors.fgMuted, fontSize: fontSizes.sm, },})
const cardDescriptionVariants = stylex.create({ solid: { color: `color-mix(in oklch, ${colorPalette.contrast} 80%, transparent)`, },})
const cardHeader = stylex.create({ base: { paddingInline: 'var(--card-padding)', paddingTop: 'var(--card-padding)', display: 'flex', flexDirection: 'column', gap: spacing._1_5, },})
const cardBody = stylex.create({ base: { padding: 'var(--card-padding)', flex: 1, display: 'flex', flexDirection: 'column', },})
const cardFooter = stylex.create({ base: { display: 'flex', alignItems: 'center', gap: spacing._2, paddingInline: 'var(--card-padding)', paddingBottom: 'var(--card-padding)', },})
export type CardSize = keyof typeof cardRootSizes
export type CardVariant = keyof typeof cardRootVariants
// defineSlotRecipe validates the shape at compile time: default values must// exist in the axis maps, and slot keys must be `styles` or a declared axisconst cardSlotRecipe = defineSlotRecipe({ slots: { root: { styles: cardRoot, sizes: cardRootSizes, variants: cardRootVariants }, header: { styles: cardHeader }, title: { styles: cardTitle, sizes: cardTitleSizes }, description: { styles: cardDescription, variants: cardDescriptionVariants }, body: { styles: cardBody }, footer: { styles: cardFooter }, }, defaultVariants: { variant: "elevated", size: "md" },});
/** * Card — recipe and component colocated in one file. `<Card.Root variant * size>` resolves the recipe once and every part inherits it through * context; each part composes via `asChild`. */const { withProvider, withContext } = createSlotRecipeContext(cardSlotRecipe);
export const Card = { // slot names resolve mechanically from the recipe maps above Root: withProvider("div", "root", "CardRoot"), Header: withContext("div", "header", "CardHeader"), Title: withContext("h3", "title", "CardTitle"), Body: withContext("div", "body", "CardBody"), Footer: withContext("div", "footer", "CardFooter"), // or an explicit resolver when a slot styles only some variants — // TypeScript errors here the moment `solid` leaves the map above Description: withContext( "p", (v) => [ cardDescription.base, v.variant === "solid" && cardDescriptionVariants.solid, ], "CardDescription", ),};