Displays a card with header, content, and footer.
❯buridan add cardUse the following to build the Card component.
from components.ui.card import cardcard.root(
card.header(
card.title(),
card.description(),
card.action(),
),
card.content(),
card.footer(),
)For manual installation, copy each of the source codes below in their respective locations.
Use size="sm" for tighter spacing throughout the card.
Props used: size on card.root.
import reflex as rx
from components.core.hugeicon import hi
from components.ui.button import button
from components.ui.card import card
def card_small() -> rx.Component:
feature_name = "Scheduled reports"
return card.root(
card.header(
card.title(feature_name),
card.description("Weekly snapshots. No more manual exports."),
),
card.content(
rx.el.ul(
rx.el.li(
hi(
"ArrowRight01Icon",
class_name="mt-0.5 size-4 shrink-0 text-muted-foreground",
),
rx.el.span("Choose a schedule (daily, or weekly)."),
class_name="flex gap-2",
),
rx.el.li(
hi(
"ArrowRight01Icon",
class_name="mt-0.5 size-4 shrink-0 text-muted-foreground",
),
rx.el.span("Send to channels or specific teammates."),
class_name="flex gap-2",
),
rx.el.li(
hi(
"ArrowRight01Icon",
class_name="mt-0.5 size-4 shrink-0 text-muted-foreground",
),
rx.el.span("Include charts, tables, and key metrics."),
class_name="flex gap-2",
),
class_name="grid gap-2 py-2 text-sm",
)
),
card.footer(
button(
"Set up scheduled reports",
size="sm",
class_name="w-full",
),
button(
"See what's new",
variant="outline",
size="sm",
class_name="w-full",
),
class_name="flex-col gap-2",
),
size="sm",
class_name="mx-auto w-full max-w-xs my-10",
)Beyond size, use the --card-spacing CSS variable directly to control section spacing and inset.
Props used: class_name (setting --card-spacing inline) on card.root.
import reflex as rx
from reflex.experimental import ClientStateVar
from components.ui.button import button
from components.ui.card import card
selected_card_spacing = ClientStateVar.create("selected_card_spacing", "4")
spacing_options = [
{
"class_name": "[--card-spacing:--spacing(4)]",
"label": "16px",
"value": "4",
},
{
"class_name": "[--card-spacing:--spacing(5)]",
"label": "20px",
"value": "5",
},
{
"class_name": "[--card-spacing:--spacing(6)]",
"label": "24px",
"value": "6",
},
{
"class_name": "[--card-spacing:--spacing(8)]",
"label": "32px",
"value": "8",
},
]
def card_spacing() -> rx.Component:
return rx.el.div(
rx.el.div(
*[
button(
item["label"],
variant="outline",
size="sm",
class_name=rx.cond(
selected_card_spacing.value == item["value"], "!bg-muted", ""
),
on_click=selected_card_spacing.set_value(item["value"]),
)
for item in spacing_options
],
class_name="flex gap-1 justify-start items-center w-full",
),
card.root(
card.header(
card.title("Login to your account"),
card.description("Enter your email below to login to your account"),
card.action(
button("Sign Up", variant="link"),
),
),
card.content(
rx.el.form(
rx.el.div(
rx.el.div(
rx.el.label(
"Email",
html_for="email-spacing",
class_name="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
),
rx.el.input(
id="email-spacing",
type="email",
placeholder="m@example.com",
required=True,
class_name="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
),
class_name="grid gap-2",
),
rx.el.div(
rx.el.div(
rx.el.label(
"Password",
html_for="password-spacing",
class_name="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
),
rx.el.a(
"Forgot your password?",
href="#",
class_name="ml-auto inline-block text-sm underline-offset-4 hover:underline",
),
class_name="flex items-center",
),
rx.el.input(
id="password-spacing",
type="password",
required=True,
class_name="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
),
class_name="grid gap-2",
),
class_name="flex flex-col gap-6",
)
)
),
card.footer(
button("Login", type="submit", class_name="w-full"),
button("Login with Google", variant="outline", class_name="w-full"),
class_name="flex-col gap-2",
),
class_name=f"[--card-spacing:--spacing({selected_card_spacing.value})]",
),
class_name="mx-auto grid w-full max-w-sm gap-4 my-10",
)Use negative margins with -mx-(--card-spacing) to let content go edge-to-edge while staying aligned with the card's inset. When edge-to-edge content sits above a footer, add -mb-(--card-spacing) on card.content to remove the section gap.
These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools.
You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it.
We may update features or limits as the service evolves. When those changes materially affect your workflow, we will notify your workspace administrators.
By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies.
import reflex as rx
from components.ui.button import button
from components.ui.card import card
def card_edge_to_edge() -> rx.Component:
return card.root(
card.header(
card.title("Terms of Service"),
card.description("Review the terms before accepting the agreement."),
),
card.content(
rx.el.div(
rx.el.p(
"These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools."
),
rx.el.p(
"You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it."
),
rx.el.p(
"We may update features or limits as the service evolves. When those changes materially affect your workflow, we will notify your workspace administrators."
),
rx.el.p(
"By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies."
),
class_name="-mx-(--card-spacing) max-h-48 space-y-4 overflow-y-scroll border-input border-t bg-muted/50 px-(--card-spacing) py-4 text-sm leading-relaxed",
),
class_name="-mb-(--card-spacing)",
),
card.footer(
button("Decline", variant="outline"),
button("Accept"),
class_name="justify-end gap-2",
),
class_name="mx-auto w-full max-w-sm",
)Add an image before card.header to create a card with a cover image — corner radii adjust automatically for first/last-child images.
Props used: none required — place rx.el.img(...) as the first child of card.root.
import reflex as rx
from components.ui.badge import badge
from components.ui.button import button
from components.ui.card import card
def card_image() -> rx.Component:
return card.root(
rx.el.div(
class_name="absolute inset-0 z-30 aspect-video bg-black/35",
),
rx.el.img(
src="https://avatar.vercel.sh/shadcn1",
alt="Event cover",
class_name="relative z-20 aspect-video w-full object-cover brightness-60 grayscale dark:brightness-40",
),
card.header(
card.action(
badge("Featured", variant="secondary"),
),
card.title("Design systems meetup"),
card.description(
"A practical talk on component APIs, accessibility, and shipping faster."
),
),
card.footer(
button("View Event", class_name="w-full"),
),
class_name="relative mx-auto w-full max-w-sm pt-0",
)card.root(
card.header(card.title("Team members")),
card.content("..."),
size="sm",
)
| Prop | Type | Default |
|---|---|---|
size |
Literal["default", "sm"] |
"default" |
class_name |
str |
"" |
For a title, description, and optional action.
card.header(
card.title("Team members"),
card.description("Manage who has access."),
card.action(button("Invite", size="sm")),
)
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |
card.title("Team members")
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |
card.description("Manage who has access to this project.")
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |
Places content in the top-right of the header (a button, badge, etc.).
card.action(button("Invite", size="sm"))
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |
card.content("Main card body content.")
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |
card.footer(button("Cancel", variant="ghost"), button("Save"))
| Prop | Type | Default |
|---|---|---|
class_name |
str |
"" |