Skip to content
Kappa
Card
@dicehub/kappav0.4.2

Card

Groups related content, context, and actions in one clear surface.

Sign in to your account

Enter your details to continue.

<script setup>
import { ref } from "vue";
import { Button } from "@dicehub/kappa/components/button";
import { Card } from "@dicehub/kappa/components/card";
import { Input } from "@dicehub/kappa/components/input";
import { Label } from "@dicehub/kappa/components/label";

const email = ref("[email protected]");
const status = ref("");
</script>

<template>
  <Card
    as="form"
    style="max-width: 23rem;"
    @submit.prevent="status = `Sign-in requested for ${email}`"
  >
    <Card.Header>
      <Card.Title>Sign in to your account</Card.Title>
      <Card.Description>Enter your details to continue.</Card.Description>
      <Card.Action><Button type="button" size="xs" variant="ghost">Register</Button></Card.Action>
    </Card.Header>
    <Card.Content>
      <Label for="email">Email</Label>
      <Input id="email" v-model="email" type="email" />
      <Label for="password">Password</Label>
      <Input id="password" type="password" />
    </Card.Content>
    <Card.Footer>
      <Button type="submit" variant="primary">Sign in</Button>
      <Button type="button" variant="outline">Continue with SSO</Button>
    </Card.Footer>
  </Card>
  <p aria-live="polite">{{ status }}</p>
</template>

Installation

Card is part of the main Kappa package. It uses native semantic elements and adds no state-machine dependency.

Barrel

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardPrimary,
  CardSecondary,
  CardTitle,
} from "@dicehub/kappa";

Granular

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardPrimary,
  CardSecondary,
  CardTitle,
} from "@dicehub/kappa/components/card";

Usage

Build a standard surface with Header, Content, and Footer. Place Action inside Header when the card needs a compact control or status.

Deployment window

Tuesday, 18:00–19:00 UTC

Ready
Services
4
Checks
12 / 12
<script setup>
import { Badge } from "@dicehub/kappa/components/badge";
import { Button } from "@dicehub/kappa/components/button";
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card as="article" style="width: 23rem;">
    <Card.Header>
      <Card.Title>Deployment window</Card.Title>
      <Card.Description>Tuesday, 18:00–19:00 UTC</Card.Description>
      <Card.Action><Badge variant="success">Ready</Badge></Card.Action>
    </Card.Header>
    <Card.Content>All 12 checks passed across four services.</Card.Content>
    <Card.Footer><Button size="sm" variant="outline">Review schedule</Button></Card.Footer>
  </Card>
</template>

Composition

Typical part hierarchy
Card.Root <div | article | section | aside | a | form>
├── Card.Header
│   ├── Card.Title
│   ├── Card.Description
│   └── Card.Action (optional)
├── Card.Content
└── Card.Footer (optional)

Card.Root (layered mode)
├── Card.Secondary (optional)
└── Card.Primary

The standard parts provide a header, content, and footer structure. Secondary and Primary provide a layered composition. Ark UI has no static Card primitive, so Kappa owns this native presentation and its semantic element choices.

  • Use the standard parts for most content, forms, status, and actions.
  • Use Secondary followed by Primary only when the layered visual hierarchy is useful.
  • Use one heading element that fits the page outline. Card.Title defaults to h3.
  • Do not nest Cards to create spacing. Use Grid or another layout container.

Examples

Layered Card

Put supporting context behind a raised primary surface.

Getting started
Project guideA short path from setup to first delivery.
<script setup>
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card style="width: 23rem;">
    <Card.Secondary as="header">Getting started</Card.Secondary>
    <Card.Primary as="article">
      <strong>Project guide</strong>
      <span>A short path from setup to first delivery.</span>
    </Card.Primary>
  </Card>
</template>

Small Card

Use the small size for compact supporting content and short actions.

Scheduled reports

Weekly snapshots without manual exports.

  • Choose daily or weekly delivery.
  • Send to a channel or teammate.
  • Include charts and key metrics.
<script setup>
import { Check } from "@lucide/vue";
import { Button } from "@dicehub/kappa/components/button";
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card as="article" size="sm" style="width: 23rem;">
    <Card.Header>
      <Card.Title>Scheduled reports</Card.Title>
      <Card.Description>Weekly snapshots without manual exports.</Card.Description>
    </Card.Header>
    <Card.Content>
      <ul>
        <li><Check aria-hidden="true" />Choose daily or weekly delivery.</li>
        <li><Check aria-hidden="true" />Send to a channel or teammate.</li>
        <li><Check aria-hidden="true" />Include charts and key metrics.</li>
      </ul>
    </Card.Content>
    <Card.Footer><Button size="xs">Set up reports</Button></Card.Footer>
  </Card>
</template>

Image Card

Place media before the header for an edge-to-edge visual introduction.

Design systems meetup

A practical session on component APIs and accessibility.

Featured
<script setup>
import { Badge } from "@dicehub/kappa/components/badge";
import { Button } from "@dicehub/kappa/components/button";
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card as="article" style="width: 23rem;">
    <img src="/event-cover.jpg" alt="People discussing a design system" />
    <Card.Header>
      <Card.Title>Design systems meetup</Card.Title>
      <Card.Description>A practical session on component APIs and accessibility.</Card.Description>
      <Card.Action><Badge>Featured</Badge></Card.Action>
    </Card.Header>
    <Card.Footer><Button size="sm">View event</Button></Card.Footer>
  </Card>
</template>

Filter Toolbar

Compose compact controls and structured data inside a standard Card.

Request origins

Recent traffic grouped by host.

OriginStatusDuration
api.example.com2xx 42128 ms
assets.example.com2xx 1986 ms
legacy.example.com4xx 7464 ms
<script setup>
import { computed, ref } from "vue";
import { Badge } from "@dicehub/kappa/components/badge";
import { Button } from "@dicehub/kappa/components/button";
import { ButtonGroup } from "@dicehub/kappa/components/button-group";
import { Card } from "@dicehub/kappa/components/card";
import { Input } from "@dicehub/kappa/components/input";

const requests = [
  { origin: "api.example.com", status: "2xx" },
  { origin: "legacy.example.com", status: "4xx" },
];
const filter = ref("all");
const query = ref("");
const filtered = computed(() => requests.filter((request) =>
  (filter.value === "all" || request.status === filter.value) &&
  request.origin.includes(query.value.trim().toLowerCase()),
));
</script>

<template>
  <Card style="max-width: 36rem;">
    <Card.Header>
      <Card.Title>Request origins</Card.Title>
      <Card.Description>Recent traffic grouped by host.</Card.Description>
    </Card.Header>
    <Card.Content>
      <div class="toolbar">
        <Input v-model="query" aria-label="Filter origins" size="sm" />
        <ButtonGroup aria-label="Status filter">
          <Button v-for="status in ['all', '2xx', '4xx']" :key="status" @click="filter = status">
            {{ status }}
          </Button>
        </ButtonGroup>
      </div>
      <div v-for="request in filtered" :key="request.origin">
        <span>{{ request.origin }}</span>
        <Badge>{{ request.status }}</Badge>
      </div>
    </Card.Content>
    <Card.Footer>Showing {{ filtered.length }} of {{ requests.length }}</Card.Footer>
  </Card>
</template>

Linked Primary Layer

Render Primary as an anchor when the complete surface has one target.

<script setup>
import { ArrowRight } from "@lucide/vue";
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card as="article" style="width: 23rem;">
    <Card.Secondary as="header">Release notes</Card.Secondary>
    <Card.Primary as="a" href="/release-notes">
      <strong>Read the component model <ArrowRight aria-hidden="true" /></strong>
      <span>One semantic anchor owns the complete primary layer.</span>
    </Card.Primary>
  </Card>
</template>

Attribute Forwarding

All Card parts accept standard HTML, ARIA, and data attributes.

Getting started

Public attributes pass to every part.

A standard content region.
<script setup>
import { Card } from "@dicehub/kappa/components/card";
</script>

<template>
  <Card data-testid="card-root" style="width: 23rem;">
    <Card.Header data-testid="card-header">
      <Card.Title data-testid="card-title">Getting started</Card.Title>
      <Card.Description data-testid="card-description">
        Public attributes pass to every part.
      </Card.Description>
    </Card.Header>
    <Card.Content data-testid="card-content">A standard content region.</Card.Content>
    <Card.Footer data-testid="card-footer">Ready</Card.Footer>
  </Card>
</template>

Accessibility

  • Card adds no widget role or keyboard behavior.
  • Choose article, section, aside, header, and footer only when the content meets native HTML sectioning rules.
  • Use as="form" when one Card contains one form. Do not nest forms.
  • Use as="a" only when the complete surface has one target. Do not place other controls inside that anchor.
  • Anchor surfaces keep a visible focus indicator and a forced-colors boundary.
  • HTML, ARIA, data attributes, and event listeners pass to the selected native element.

API Reference

Card

Outer surface for standard, layered, or direct content.

PropTypeDefaultDescription
as"div" | "article" | "section" | "aside" | "a" | "form""div"Native element rendered by the outer surface.
size"sm" | "base""base"Controls spacing and the type scale.
default slotslot—Standard Card parts, layered parts, or direct surface content.

Standard Parts

PartSupported asDefaultDescription
Card.Header"div" | "header""div"Title, description, and optional action layout.
Card.Title"h2"–"h6" | "p" | "div""h3"Card heading.
Card.Description"p" | "div""p"Supporting text below the title.
Card.Action"div""div"Header action aligned to the inline end.
Card.Content"div" | "section""div"Main content region.
Card.Footer"div" | "footer""div"Actions or supporting content at the bottom.

Layered Parts

PartSupported asDefaultDescription
Card.Secondary"div" | "header" | "p""div"Supporting layer behind the main surface.
Card.Primary"div" | "article" | "section" | "a""div"Raised main-content surface.

Data Slots

SlotDescription
cardOuter surface
card-headerHeader layout
card-titleTitle
card-descriptionDescription
card-actionHeader action
card-contentMain content
card-footerFooter
card-secondarySupporting layer
card-primaryRaised primary layer

Exports

ExportDescription
CardCompound root with all standard and layered parts.
CardRootNamed outer surface export.
CardHeader / CardTitle / CardDescription / CardActionNamed header composition exports.
CardContent / CardFooterNamed body and footer exports.
CardPrimary / CardSecondaryNamed layered-surface exports.
Card*Props / Card*Slots / CardSizePublic prop, slot, and size contracts.
resolveCard*Safe runtime resolvers for sizes and semantic elements.