---
title: Card
description: Structured content container with optional header, body, footer, and action slots.
sidebar:
  order: 6
search:
  tags: [container, panel, content, surface]
---

# Card

> Structured content container with optional header, body, footer, and action slots.

## Import

```tsx
import { Card } from 'moraine'
```

## Slot Structure

Structured content container with optional header, body, and footer sections.

```text
root
├── header (optional)
│   ├── title (optional)
│   ├── description (optional)
│   └── action (optional)
├── body (optional)
└── footer (optional)
```

## Examples

### Default

Create project form card from coss/ui.

```tsx
function Default() {
  const frameworkOptions = [
    { label: 'Vite', value: 'vite' },
    { label: 'Solid Start', value: 'solid-start' },
    { label: 'Tanstack Start', value: 'tanstack-start' },
    { label: 'Astro', value: 'astro' },
  ]

  return (
    <Card
      title="Create project"
      description="Deploy your new project in one-click."
      footer={
        <>
          <Button class="w-full" type="submit">
            Deploy
          </Button>
          <div class="text-xs text-muted-foreground m-a flex gap-1 items-center">
            <Icon name="i-lucide-circle-alert" class="h-lh shrink-0 size-3" />
            <p>This will take a few seconds to complete.</p>
          </div>
        </>
      }
      class="max-w-xs w-full"
      classes={{ footer: 'flex flex-col gap-3' }}
    >
      <div class="flex flex-col gap-4">
        <FormField label="Name">
          <Input placeholder="Name of your project" />
        </FormField>
        <FormField label="Framework">
          <Select options={frameworkOptions} value="vite" />
        </FormField>
      </div>
    </Card>
  )
}
```

### Sizes

Default and compact size presets.

```tsx
function Sizes() {
  return (
    <div class="flex gap-2">
      <Card
        compact
        title="Small Card"
        description="Compact"
        footer={<Button size="sm">Action</Button>}
        class="h-fit max-w-xs"
      >
        <p class="text-sm opacity-85">Compact spacing for dense layouts and sidebars.</p>
      </Card>

      <Card
        title="Default Card"
        description="Default"
        footer={<Button size="sm">Action</Button>}
        class="h-fit max-w-xs"
      >
        <p class="text-sm opacity-85">Standard spacing for normal form and dashboard cards.</p>
      </Card>
    </div>
  )
}
```

### With Image

Media-first card using body slot customization.

```tsx
function WithImage() {
  return (
    <div class="max-w-sm">
      <Card
        classes={{ header: 'pb-6' }}
        header={
          <img
            src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
            alt="Landscape by mymind on Unsplash"
            class="rounded-t-2xl w-full aspect-video object-cover brightness-60 grayscale"
          />
        }
        footer={<Button class="w-full">Open</Button>}
      >
        <h3 class="font-semibold">Beautiful Landscape</h3>
        <p class="text-sm text-muted-foreground mt-1">
          A compact media card style adapted to the sealed Moraine Card API.
        </p>
      </Card>
    </div>
  )
}
```

### Header Action

Custom action area inside the header slot.

```tsx
function HeaderAction() {
  return (
    <div class="w-lg">
      <Card
        title="Meeting Notes"
        description="Transcript summary from the latest client sync."
        action={
          <Button size="sm" variant="secondary">
            Transcribe
          </Button>
        }
        footer={
          <div class="flex gap-2 w-full justify-end">
            <Button size="sm" variant="outline">
              Dismiss
            </Button>
            <Button size="sm">Save</Button>
          </div>
        }
      >
        <ol class="text-sm pl-5 list-decimal opacity-85 flex flex-col gap-1.5">
          <li>Dashboard redesign should prioritize mobile layouts.</li>
          <li>Timeline target is six weeks with weekly milestones.</li>
          <li>Next review meeting is scheduled for Tuesday morning.</li>
        </ol>
      </Card>
    </div>
  )
}
```

## API Reference

### Attributes

#### `root`

Card container that frames the header, body, and footer regions.

#### `header`

Top region for title, description, custom header content, and actions.

#### `title`

Primary heading rendered in the card header.

#### `description`

Supporting text rendered below the card title.

#### `action`

Header action region, typically used for buttons or menus.

#### `body`

Main content region for the card children.

#### `footer`

Bottom region for secondary actions or summary content.

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| action | JSX.Element | — | Content to render in the action slot (usually a button in the header). |
| children | JSX.Element | — | Children of the card. |
| class | ClassValue | — | Class applied to the component root or trigger element. |
| classes | CardT.Classes \| undefined | — | — |
| compact | boolean \| undefined | false | Whether to use a compact layout. |
| description | JSX.Element | — | Description of the card. |
| footer | JSX.Element | — | Content to render in the footer slot. |
| header | JSX.Element | — | Content to render in the header slot, overrides title/description. |
| ref | JSX.HTMLElementTags["div"] extends { ref?: infer Ref; } ? Ref : never \| undefined | — | — |
| style | JSX.CSSProperties \| undefined | — | — |
| styles | CardT.Styles \| undefined | — | — |
| title | JSX.Element | — | Title of the card. |

### Data Attributes

State and slot attributes exposed for styling hooks and selectors.

| Attribute | Type | Description |
| --- | --- | --- |
| data-slot | string | Identifies the rendered slot for styling hooks and selectors. |
