Card
Group related content and actions on a surface.
use herogpui::components::card::{Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle};Card on docs.rsSource at v0.14.0
Usage
Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Link, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![
Card::new()
.w(px(400.))
.child(
gpui::svg()
.size(px(24.))
.path(icons::KEY)
.text_color(cx.colors().accent.color),
)
.child(
CardHeader::new()
.child(CardTitle::new().child("Become an Acme Creator!"))
.child(
CardDescription::new().child(CARD_USAGE_DESCRIPTION),
),
)
.child(
CardFooter::new().child(
Link::new("card-usage-link")
.label("Creator Hub")
.href("https://example.com")
.icon(
gpui::svg()
.size(px(12.))
.path(icons::EXTERNAL_LINK)
.text_color(cx.colors().link),
),
),
)
.into_any_element()
])Also calls CARD_USAGE_DESCRIPTION (included when you copy).
An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardVariant, Size, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let card = |variant: CardVariant| {
Card::new()
.variant(variant)
.w(px(260.))
.radius(px(4.))
.child(
CardHeader::new()
.child(CardTitle::new().child("Daily report"))
.child(CardDescription::new().child("Traffic summary for the week")),
)
.child(CardContent::new().child("Sessions are up 12% week over week."))
.child(
CardFooter::new().child(
Button::new(format!("card-{variant:?}-cta"))
.label("View")
.size(Size::Sm)
.variant(Variant::Tertiary),
),
)
};
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(CardVariant::ALL.iter().map(|v| card(*v)))An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![Card::new()
.w(px(420.))
.child(
CardContent::new().child(
gpui::div()
.flex()
.items_center()
.gap(px(16.))
.child(
gpui::div()
.size(px(72.))
.flex_shrink_0()
.rounded(px(12.))
.bg(cx.colors().default.color),
)
.child(
gpui::div()
.flex()
.flex_col()
.gap(px(4.))
.child(gpui::div().child("Weekly digest"))
.child(
gpui::div()
.text_size(px(12.5))
.text_color(cx.colors().muted)
.child("Every Monday, 9am"),
),
),
),
)
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Avatar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Size, extend};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![Card::new()
.w(px(200.))
.child(
gpui::div()
.size(px(56.))
.rounded(extend::soft_radius(cx))
.bg(cx.colors().default.color),
)
.child(
CardHeader::new()
.child(CardTitle::new().child("Indie Hackers"))
.child(CardDescription::new().child("148 members")),
)
.child(
CardFooter::new()
.child(
Avatar::new("card-martha").name("Martha").size(Size::Sm)
)
.child("By Martha"),
)
.into_any_element()])An element expression with window: &mut Window and cx: &mut App in scope.
use herogpui::prelude::{ActiveTheme, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![Card::new()
.w(px(280.))
.child(
CardContent::new().child(
gpui::div()
.h(px(140.))
.w_full()
.rounded(px(12.))
.bg(cx.colors().default.color),
),
)
.child(CardFooter::new().child("A placeholder for cover art."))
.into_any_element()])Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, InputType, TextField};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
gpui::div()
.flex()
.flex_wrap()
.items_center()
.justify_center()
.gap(px(12.))
.children(vec![Card::new()
.w(px(320.))
.child(CardHeader::new().child(CardTitle::new().child("Sign in")))
.child(
CardContent::new().child(
gpui::div()
.flex()
.flex_col()
.gap(px(12.))
.child(
TextField::new(self.demo_text("card-email", "", cx))
.label("Email")
.input_type(InputType::Email)
.full_width(),
)
.child(
TextField::new(self.demo_text(
"card-password",
"",
cx
))
.label("Password")
.input_type(InputType::Password)
.full_width(),
),
),
)
.child(
CardFooter::new()
.child(Button::new("card-signin").label("Sign in")),
)
.into_any_element()])Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
/// v3's Card "Usage" copy. See [`ALERT_USAGE_DESCRIPTION`].
const CARD_USAGE_DESCRIPTION: &str = concat!(
"Visit the Acme Creator Hub to sign up today and start earning ",
"credits from your fans and followers.",
);Anatomy
Rust types
Card is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Card looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
variant(CardVariant) | CardVariant::Transparent | CardVariant::Default | CardVariant::Secondary | CardVariant::Tertiary | Semantic variant indicating prominence level. Transparent paints nothing — no border, no background, no shadow, the full content box — while every other level fills and carries the surface shadow. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 6 entries ported, 7 partial, 6 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
variant( | CardVariant:: | CardVariant:: | Semantic variant indicating prominence level. Transparent paints nothing — no border, no background, no shadow, the full content box — while every other level fills and carries the surface shadow. |
ParentElement::Partial | AnyElement | — | Card content; the parts compose through ParentElement::extend and the root wraps them in the padded column with the capped container radius. |
Not ported6 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
Card.className | |
Card.Header.className | For the header. |
Card.Title.className | For the title. |
Card.Description.className | For the description. |
Card.Content.className | For the content. |
Card.Footer.className | For the footer. |
Parts
| Part | Description |
|---|---|
Card | Composition root and data-slot owner; the padded column at a 12px part gap with the capped container radius. `overflow-visible` upstream, so adds no clipping; the variant chooses the fill and whether the surface shadow applies. |
CardHeader | Header section container; a plain flex column, with no text style of its own. |
CardTitle | Title part: 14px medium text on the foreground colour, 24px leading. Renders an h3; renders the same typography on a plain div. |
CardDescription | Muted description part: 14px text at 20px leading. Renders a p; renders the same typography on a plain div. |
CardContentPartial | Content column at a four-pixel gap. The upstream flex-1 is dropped: the pinned-geometry test in tests/card_deep.rs measures the card as an auto-height column hugging its parts, which flex-1 regresses. |
CardFooter | Footer row with centered items; the card's gap separates it from the other parts and the caller composes the row's contents. |