Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Card

Layer: molecule · Path: src/molecules/card.rs · Exports: card::{Card, CardSize}

An elevated Surface with an optional header (title + description + a top-right action slot), arbitrary content (a closure), and an optional footer separated by a divider. size scales the internal padding and gaps. Models the shadcn Card (Header / Content / Footer / CardAction).

Design

  • Purpose / when to use — Group related content into a raised panel: a settings block, a summary, a property editor section.

  • AnatomySurface::elevated() (padded by size) → vertical stack of:

    1. Header (only if title/description/action set): horizontal row of a vertical Heading title + muted caption Text description, with the action closure laid out right-to-left at the top-right.
    2. Content — your content closure, always run.
    3. Footer (if set): a Divider then your footer closure.
  • Sizes

    CardSizepadheader/footer gap
    DefaultSPACE_4SPACE_3
    SmSPACE_3SPACE_2
  • Tokens / layout consumedcore::SPACE_4 / SPACE_3 / SPACE_2 / SPACE_1; elevation from Surface. See tokens.

API

MethodEffect
Card::new() -> SelfEmpty card, CardSize::Default. (Default also available.)
.title(title: impl Into<String>) -> SelfHeader title (renders a Heading).
.description(description: impl Into<String>) -> SelfHeader sub-text (muted caption).
.action(action: impl FnOnce(&mut Ui) + 'a) -> SelfTop-right header slot — a button/menu/badge.
.footer(footer: impl FnOnce(&mut Ui) + 'a) -> SelfFooter slot below a divider.
.size(size: CardSize) -> SelfSet the spacing scale.
.sm() -> SelfSugar for CardSize::Sm.
.show(self, ui: &mut Ui, content: impl FnOnce(&mut Ui)) -> ResponseRender; content is the card body. Returns the surface Response.

CardSizeDefault (default), Sm.

Usage

#![allow(unused)]
fn main() {
use ouroboros_ui::molecules::Card;
use ouroboros_ui::atoms::Text;

// minimal
Card::new().title("Compact").show(ui, |ui| {
    Text::new("Body content.").show(ui);
});
}
#![allow(unused)]
fn main() {
use ouroboros_ui::molecules::Card;
use ouroboros_ui::atoms::{Button, Text};
use ouroboros_ui::egui_phosphor::light;

// realistic — header action + footer buttons + closure body
Card::new()
    .title("Project settings")
    .description("Manage your project preferences")
    .action(|ui| {
        Button::new("")
            .icon_left(light::DOTS_THREE)
            .icon_only()
            .ghost()
            .sm()
            .id_source("card_menu")
            .show(ui);
    })
    .footer(|ui| {
        ui.horizontal(|ui| {
            Button::new("Save").id_source("card_save").show(ui);
            Button::new("Cancel").ghost().id_source("card_cancel").show(ui);
        });
    })
    .show(ui, |ui| {
        Text::new("Card body content goes here.").show(ui);
    });
}

Composition

Composes Surface + Heading + Text + Divider. Body, action, and footer are caller-supplied closures. It never paints — see the guards.

Notes

  • Card<'a> carries a lifetime: the action/footer closures are boxed (Box<dyn FnOnce(&mut Ui) + 'a>) and may borrow from the surrounding scope.
  • content is a plain impl FnOnce(&mut Ui) (not boxed) and always runs, even with no header/footer.
  • The header is omitted entirely when none of title/description/action are set.
  • Give interactive widgets inside the slots stable id_sources when multiple cards share a frame.