Mosmox UI
Current version
GitHubnpmjs.com
Content & Media

Card

A flexible surface for grouping related content, actions and media.

Card groups related content into a clear visual surface. It can be a simple content container, an interactive card, a link, a horizontal media card, a full-bleed background-media card, a table-like row, or a loading state. All content props accept ReactNode, so buttons, tags, icons, avatars and other components can be composed inside it.

Component model

The regular composition is media → header → body → footer. The generated header contains title, description, titleIcon, badge and actions; supplying header replaces that generated header. layout="row" replaces the regular header/body composition with the columns row, while footer remains available.

Basic card

<Card title="Project overview" description="A short description of the project.">
  Review the latest activity and settings for this project.
</Card>

The header can also be supplied as custom content. When header is provided, it replaces the generated title, description, badge and actions header.

<Card
  header={<div>Custom header content</div>}
  footer={<span>Updated just now</span>}
>
  Card content goes here.
</Card>

Variants and sizes

  • variant="default" — surface with a control border.
  • variant="outlined" — transparent surface with a border.
  • variant="filled" — tinted control surface.
  • variant="ghost" — no visible border or surface.
  • variant="elevated" — borderless surface with a stronger elevation shadow.
  • variant="flat" — borderless, low-contrast filled surface.
  • size="sm", default and lg control spacing and typography.
<Card variant="filled" size="sm" title="Compact card">Compact content.</Card>
<Card variant="outlined" size="lg" title="Large card">More spacious content.</Card>
<Card variant="elevated" title="Elevated card">A card that needs visual emphasis.</Card>
<Card variant="flat" title="Flat card">A quiet card for dense layouts.</Card>

title, description, titleIcon, badge and actions create a standard header. footer renders a separated footer row and accepts any React content.

<Card
  title="Team members"
  description="People with access to this workspace."
  badge={<Badge tone="secondary" count={12} />}
  titleIcon={<Users aria-hidden="true" size={16} />}
  actions={<Button size="sm" variant="outline">Manage</Button>}
  footer={<><span>Last synced today</span><Button size="sm">View all</Button></>}
>
  Member list content.
</Card>

Interactive cards

Use interactive with onClick for an action card, or href for a link card. Interactive cards support keyboard activation and visible focus. Do not place another interactive control over the whole card when using href or onClick; keep secondary actions in a non-conflicting area.

<Card interactive onClick={() => openProject('design')} title="Design system">
  Open the project details.
</Card>

<Card href="/projects/design" title="Design system">
  Navigate to the project.
</Card>

Media and layout

media places an image, illustration or other visual in the card. Vertical cards place media at the top by default; set mediaPosition="bottom" to place it below the content. Horizontal cards place media on the left by default; set mediaPosition="end" to place it on the right.

<Card
  orientation="horizontal"
  media={<img alt="Workspace preview" src="/workspace-preview.png" />}
  title="Workspace preview"
  description="A horizontal media layout."
>
  Use this layout for previews and featured content.
</Card>

<Card
  orientation="horizontal"
  mediaPosition="end"
  media={<img alt="Workspace preview" src="/workspace-preview.png" />}
  title="Media on the right"
>
  A horizontal card with the media aligned to the end.
</Card>

<Card
  mediaPosition="bottom"
  media={<img alt="Workspace preview" src="/workspace-preview.png" />}
  title="Media below content"
>
  A vertical editorial layout with the media at the bottom.
</Card>

<Card
  mediaPosition="background"
  backgroundContentPosition="top"
  backgroundContentWidth="100%"
  media={<img alt="Mountain landscape" src="/mountains.jpg" />}
  title="Featured story"
  description="Content over a full-bleed image."
>
  Use this variant for editorial highlights and featured content.
</Card>

mediaPosition="background" is a vertical layout. The media fills the card, a gradient improves text contrast, and the header/body/footer remain above the image. Images use object-fit: cover.

Use backgroundContentPosition to place the text block at the top, bottom, left or right edge of the background image. Use backgroundContentWidth to control its readable measure. It accepts full (or 100%), percentages, pixels, or any valid CSS width such as 420px or min(70%, 520px).

<Card
  mediaPosition="background"
  backgroundContentPosition="bottom"
  backgroundContentWidth="min(72%, 520px)"
  media={<img alt="Mountain landscape" src="/mountains.jpg" />}
  title="Featured story"
  description="A controlled text measure over the image."
>
Keep supporting content near the lower edge while preserving the image around it.
</Card>

The position values are interpreted by layout: top and bottom are vertical media placements, start and end are horizontal media placements, and background makes the media fill the card. On narrow screens horizontal cards switch to a stacked flow.

Row cards and columns

Use layout="row" with columns to render one full-width record with table-like columns. Each column accepts a label, arbitrary React content, alignment, and an optional width. Labels are hidden by default; set columnHeaders to show compact column headings.

const columns = [
  { key: 'name', label: 'Project', content: <strong>Atlas CRM</strong> },
  { key: 'owner', label: 'Owner', content: 'Product team' },
  { key: 'status', label: 'Status', content: <Tag tone="success">Active</Tag>, align: 'center' },
  { key: 'updated', label: 'Updated', content: '2 minutes ago', align: 'end' },
];

<Card layout="row" fullWidth columns={columns} columnHeaders columnSizing="equal" />

Supported sizing strategies:

<Card layout="row" columns={columns} columnSizing="equal" />
<Card layout="row" columns={columns} columnSizing="content" />
<Card layout="row" columns={columns} columnSizing="between" />
<Card layout="row" columns={columns} columnSizing="fixed" columnWidths={[180, '1fr', 120, 160]} />
<Card layout="row" columns={columns} columnSizing="flex" />
  • equal distributes all columns evenly;
  • content sizes columns according to their content;
  • between keeps the first and last columns close to the edges and lets the middle area grow;
  • fixed uses columnWidths or individual column width values;
  • flex distributes the available space while allowing long content to shrink.

Set columnHeaders={false} for a compact row without labels. Column content can include buttons, tags, avatars, icons, progress indicators, or any other React component. On narrow screens row columns stack vertically and end/center alignment returns to the start edge.

const actionColumns = [
  { key: 'name', label: 'Workspace', content: <strong>Design system</strong> },
  { key: 'description', label: 'Description', content: 'Shared components and tokens.' },
  { key: 'action', content: <Button size="sm" variant="outline">Open</Button>, align: 'end' },
];

<Card
  layout="row"
  fullWidth
  columns={actionColumns}
  columnHeaders
  columnSizing="fixed"
  columnWidths={[180, '1fr', 110]}
  variant="outlined"
/>

Loading, disabled and selection states

  • loading blocks interaction and displays the token-based loading indicator.
  • disabled prevents interaction and communicates unavailable state.
  • selected marks an active card with the primary focus ring.
  • fullWidth stretches the card to its parent width.

loading renders an accessible role="status" loading layer and disables pointer interaction. disabled prevents click handling and communicates unavailable content. selected adds the selected border and focus treatment. For interactive cards, Enter and Space invoke onClick; links use the native anchor behavior. Do not make the entire card interactive and place a conflicting interactive control over the same surface.

Accessibility and semantics

  • Use a meaningful title or an explicit aria-label for standalone cards.
  • Use as="section" or as="div" when the surrounding document structure requires it; the default element is article.
  • href renders an anchor and takes precedence over custom keyboard activation.
  • title and description receive generated IDs and are connected to the card with aria-labelledby and aria-describedby.
  • Images supplied through media should include useful alt text when they convey information, or alt="" when decorative.

API Reference

PropTypeDefaultDescription
childrenReactNode—Main card content.
aria-labelstring—Accessible name when the visible title is not sufficient.
titleReactNode—Generated header title.
descriptionReactNode—Supporting header text.
titleIconReactNode—Icon displayed before the title.
badgeReactNode—Header badge or status content.
actionsReactNode—Header actions.
headerReactNode—Fully replaces the generated header.
footerReactNode—Footer content separated by a border.
mediaReactNode—Media displayed above or beside the content.
mediaPositiontop | bottom | start | end | backgroundtop for vertical, start for horizontalControls media placement. start/end apply to horizontal cards; top/bottom/background apply to vertical cards.
backgroundContentPositiontop | bottom | left | righttopPosition of the content block when mediaPosition="background".
backgroundContentWidthnumber | string100%Width of the background-media content block. Numbers are pixels; strings may be full, percentages, or valid CSS widths.
variantdefault | outlined | filled | ghost | elevated | flatdefaultSurface treatment.
sizesm | default | lgdefaultSpacing and typography density.
orientationvertical | horizontalverticalCard layout direction.
layoutstacked | rowstackedUses the regular card composition or a table-like row composition.
columnsCardColumn[]—Row-card columns with optional labels, content, widths, and alignment.
columnHeadersbooleanfalseShows compact labels above row-column content.
columnSizingequal | content | fixed | between | flexflexColumn width strategy in row layout.
columnWidths(number | string)[]—Explicit CSS widths used by fixed sizing.
interactivebooleaninferredEnables click behavior, hover and keyboard focus.
onClick(event) => void—Action for an interactive card.
onKeyDown(event) => void—Optional keyboard event handler. It runs before the built-in Enter/Space activation.
hrefstring—Renders the card as a link.
selectedbooleanfalseShows selected state.
loadingbooleanfalseShows a loading overlay and blocks interaction.
disabledbooleanfalseDisables the card.
fullWidthbooleanfalseUses the available width.
asarticle | div | sectionarticleSemantic element for non-link cards.

All visual values use the shared theme tokens, including surface, text, border, focus, primary and spacing tokens.

CardColumn has the shape { key?: string; label?: ReactNode; content: ReactNode; width?: number | string; align?: 'start' | 'center' | 'end' }.

Type reference

TypeValuesMeaning
CardVariantdefault, outlined, filled, ghost, elevated, flatSurface and border treatment.
CardSizesm, default, lgCompact, standard or spacious density.
CardOrientationvertical, horizontalStacked content or media beside content.
CardMediaPositiontop, bottom, start, end, backgroundMedia placement within the selected orientation.
CardBackgroundContentPositiontop, bottom, left, rightContent block edge for background media.
CardColumnSizingequal, content, fixed, between, flexGrid strategy for row columns.
CardColumnAlignstart, center, endHorizontal alignment of a row column.
CardElementarticle, div, sectionSemantic element used when the card is not a link.

CardColumn fields

FieldTypeDefaultDescription
keystringindexStable React key for the column.
labelReactNode—Optional compact heading, rendered only when columnHeaders is true.
contentReactNoderequiredColumn value or composed UI content.
widthnumber | stringstrategy-dependentPer-column width; numbers are pixels and strings are CSS grid track values.
alignstart | center | endstartColumn content alignment.