Appica UIUI 1.1.0

Card

A flexible content container for a title, description, media, and actions.

A wildflower meadow below pine forest and snow-capped peaks

Golden hour in the valley

Three nights in a timber cabin at the treeline, with meadow trails and the peaks at your door.

Usage

Card is a layout container, not a widget - it has no state, no interaction, and stays renderable from a Server Component. Compose it from its parts, all under @appica/ui-react/card:

  • Card - the root. Owns the frame, the inset, and the radius every other corner scales from. It renders two elements: the outer frame and the inner content wrapper, a flex column that holds the slots.
  • CardMedia - a clipped box for an image or video. Place it above the header or below the footer.
  • CardHeader - the text column. It stretches, which is what pins CardFooter to the bottom of a fixed-height card.
  • CardTitle - the headline (<h3>).
  • CardDescription - the supporting text (<p>).
  • CardFooter - a row for actions that stacks on narrow viewports.

Every part is optional. A card can be nothing but a CardMedia, or nothing but a CardHeader.

One radius, everywhere

--card-radius is the card's own corner (the one on the content wrapper) and the only number you ever set:

The frame and the inset media scale off it proportionally: the frame rounds at ×4/3 and inset media at ×3/4. That's deliberate - subtracting the padding instead would leave inset media on a hairline corner at the default radius, and collapse it entirely below that. Retune one value and the whole nest stays in proportion.

Examples

Default

The most basic setup - no props, just a header and a footer.

Frame

frame="solid" wraps the content in a band of background-subtle and softens the inner hairline to border-muted. Leave it off (the default) unless the card needs that extra separation from the page.

Glass frame

frame="glass" swaps the band for a translucent, blurred one and drops the inner border. Glass only exists relative to what's behind it - put the card over a photo, a gradient, or a colored section, never on flat page background.

Media

CardMedia clips whatever you put in it, above the header or below the footer. With the default inset, media floats inside the content wrapper with all four corners rounded. With inset={false}, the header and footer take the full gutter themselves and media runs edge to edge - the content wrapper's own overflow-hidden clips it, so a top image rounds only its top corners and a bottom image only its bottom ones, in either writing direction.

Video

Anything inside CardMedia is clipped the same way. Direct <img> and <video> children are stretched and object-cover'd for you, so a fixed height on CardMedia is all the sizing you need.

There's no orientation prop - the content wrapper is a flex column, so turning a card sideways is one Tailwind class on it via contentProps. Wrap the header and footer in a plain div so they keep stacking while the media sits alongside.

CardMedia is already position: relative, so a next/image with fill drops straight in. The whole card renders as an <article> via render, and the title wraps a next/link so only the headline is clickable - see Accessibility for why that beats an onClick on the root.

Overlay

For a card that is an image, position CardMedia absolutely - inset-2 when the card is inset, inset-0 when it isn't - and let CardHeader stack above it. Add a scrim inside the media for legible text.

Profile

Any content is welcome inside CardHeader; it's a plain flex column. Here an Avatar leads a centered profile card.

Empty state

Reach contentProps to restyle the surface itself - a dashed border and a subtle fill turn a card into a placeholder. A Thumbnail in an icon variant carries the visual weight.

Product card

CardHeader is a plain flex column, so anything can live in it - here a price row, a ToggleGroup of sizes, and a NumberField. The badge and wishlist toggle are positioned inside CardMedia, which is already relative.

Form in a card

render={<form />} makes the card itself the form element, so Fields and the submit button need no extra wrapper.

Radius

Changing --card-radius retunes the card and its inset media together, in one place.

RTL

Every Appica UI component supports right-to-left layouts out of the box. Set the dir attribute on a container (commonly your <html> element) so CSS logical properties resolve correctly, and wrap your tree in DirectionProvider so direction-aware behavior follows the same direction.

Card is built entirely from logical padding and flex ordering, so the footer's actions flow from the right and text aligns to the start edge with no direction-specific classes. Flush media is clipped by the content wrapper rather than by fixed top/bottom radii, so it follows the writing direction too. For setup details and caveats, see the RTL guide.

مرج من الأزهار البرية أسفل غابة صنوبر وقمم مكسوة بالثلوج

ساعة ذهبية في الوادي

ثلاث ليالٍ في كوخ خشبي عند حد الأشجار، مع مسارات المروج والقمم على بابك.

API reference

Card

The root. Renders the outer frame plus an inner content wrapper, and publishes the one custom property the other parts scale from.

Any other <div> attribute is forwarded to the root.

--card-radius

The card's corner radius, defaulting to var(--radius-xl). Set it with an arbitrary-property class on Card (or anywhere above it) and the frame (×4/3) and inset media (×3/4) scale with it.

CardMedia

A clipped box for an image or video. Renders a <div>; direct <img> and <video> children get size-full object-cover.

CardHeader

The text column. Renders a <div> that stretches to fill the content wrapper, which is what pins the footer down.

CardTitle

The headline. Renders an <h3>.

CardDescription

The supporting text. Renders a <p> styled text-foreground-muted text-sm to pair with CardTitle; override with className.

CardFooter

A row for actions. Renders a <div> that stacks in reverse order below the sm breakpoint, so the primary action sits on top on narrow screens.

Accessibility

  • Card renders a plain <div> with no implicit role - it's a visual grouping, not a landmark. Use render={<article />} when the card is self-contained content, or render={<li />} inside a list, so the structure is exposed to assistive tech.
  • CardTitle is an <h3> so a page of cards reads as a coherent outline. If <h3> is the wrong level for your page, change it with render={<h2 />} rather than restyling a <div>.
  • Make the whole card clickable only if you also give it a real control: put an <a> or <button> on the title and stretch its hit area (after:absolute after:inset-0) instead of adding onClick to the root - that keeps the link keyboard-reachable and announced.
  • Decorative media should carry alt="" so screen readers skip it; describe meaningful imagery in the alt text, not in the card copy alone.
  • A video that autoplays in CardMedia must be muted, playsInline, short, and purely decorative - Safari won't even paint a frame otherwise. Anything the user is meant to actually watch needs controls and no autoPlay.
  • The card adds no animation, so there is nothing to suppress for users who prefer reduced motion.

© 2026 Appica UI. A free component library, crafted by the Appica team.