Tessera UI

Card

A flexible surface container for grouping related content. Four variants (elevated/outlined/filled/ghost), five intents, six rounded options, five sizes, horizontal layout, interactive states, and LTR/RTL support.

Installation

pnpm add @tessinaui/ui

Usage

import {
  Card,
  CardMedia,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
  CardDivider,
} from "@tessinaui/ui";
{/* Basic card */}
<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
    <CardDescription>Description</CardDescription>
  </CardHeader>
  <CardContent>Content</CardContent>
  <CardFooter>
    <Button variant="primary">Action</Button>
  </CardFooter>
</Card>

{/* Outlined with intent */}
<Card variant="outlined" intent="success">
  <CardHeader>
    <CardTitle>Success</CardTitle>
  </CardHeader>
</Card>

{/* Card with media */}
<Card rounded="lg" className="overflow-hidden w-72">
  <CardMedia src="/image.jpg" alt="Cover" aspectRatio="video" position="top" />
  <CardHeader>
    <CardTitle>Article title</CardTitle>
  </CardHeader>
</Card>

{/* Interactive card */}
<Card interactive onClick={() => navigate('/details')}>
  <CardContent>Click me</CardContent>
</Card>

{/* Horizontal layout */}
<Card horizontal className="max-w-lg overflow-hidden">
  <CardMedia position="start" className="w-32 bg-secondary" />
  <div className="flex flex-col flex-1">
    <CardHeader>
      <CardTitle>Horizontal card</CardTitle>
    </CardHeader>
    <CardContent>Content beside media</CardContent>
  </div>
</Card>

{/* RTL */}
<Card dir="rtl" variant="outlined">
  <CardHeader>
    <CardTitle>عنوان البطاقة</CardTitle>
  </CardHeader>
</Card>

Playground

Preview

Showcase

Preview

API Reference

Card Props

PropTypeDefaultDescription
variant"elevated" | "outlined" | "filled" | "ghost""elevated"Visual surface style
intent"none" | "error" | "warning" | "success" | "info""none"Semantic intent color applied to the card surface
size"xs" | "sm" | "md" | "lg" | "xl""md"Controls padding of all inner sections
rounded"none" | "sm" | "md" | "lg" | "xl" | "full""md"Corner radius
width"narrow" | "default" | "wide" | "full""default"Max-width constraint
shadow"none" | "sm" | "md" | "lg""md" for elevated, "none" otherwiseDrop shadow depth
interactivebooleanfalseAdds hover / active / focus-ring states
disabledbooleanfalseDims the card and disables pointer events
horizontalbooleanfalseSwitches internal flex direction to row
dir"ltr" | "rtl""ltr"Text direction
classNamestringAdditional class on the root element

CardMedia Props

PropTypeDefaultDescription
srcstringImage source URL
altstring""Image alt text
aspectRatio"auto" | "video" | "4/3" | "1/1" | "2/1" | "3/4""video"Aspect ratio of the media container
position"top" | "bottom" | "start" | "end" | "fill""top"Edge the media abuts — determines which corners are rounded
childrenReactNodeCustom media content (video, iframe, etc.) replaces the default <img>

CardHeader Props

PropTypeDefaultDescription
iconReactNodeIcon / illustration rendered above (or inline with) the title
inlineIconbooleanfalseLays out icon and title text in a horizontal row

CardFooter Props

PropTypeDefaultDescription
verticalbooleanfalseStacks footer items vertically
align"start" | "center" | "end" | "between""start"Alignment of footer items

Variants

ValueStyle
"elevated"bg-card with drop shadow (default shadow-md)
"outlined"bg-background with border-border — flat with visible border
"filled"bg-secondary (or intent-light color) — tinted surface
"ghost"Transparent — no border, no shadow

Notes

  • Section paddingCardHeader, CardContent, and CardFooter all read size from context and apply consistent padding. Override per-section with className.
  • CardMedia rounding — use position to control which corners are rounded on the media figure. Set position="start" for the left edge of horizontal cards; it uses logical CSS properties so it flips automatically in RTL.
  • Interactive cards — when interactive is set and the card contains nested buttons or links, prefer the stretched-link pattern (absolute-positioned <a>) rather than onClick on the card root to avoid nested interactive element accessibility issues.
  • Horizontal layout — set horizontal on the Card root, then use CardMedia with position="start" (or "end") and wrap remaining sections in a <div className="flex flex-col flex-1">.
  • RTLdir="rtl" is applied to the root and propagates to all children. Logical CSS properties (rounded-s-*, rounded-e-*) ensure media rounding flips correctly.

On this page