<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
- 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
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.PrimaryThe 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.
<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.
<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.
<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.
<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.
| Prop | Type | Default | Description |
|---|---|---|---|
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 slot | slot | — | Standard Card parts, layered parts, or direct surface content. |
Standard Parts
| Part | Supported as | Default | Description |
|---|---|---|---|
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
| Part | Supported as | Default | Description |
|---|---|---|---|
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
| Slot | Description |
|---|---|
card | Outer surface |
card-header | Header layout |
card-title | Title |
card-description | Description |
card-action | Header action |
card-content | Main content |
card-footer | Footer |
card-secondary | Supporting layer |
card-primary | Raised primary layer |
Exports
| Export | Description |
|---|---|
Card | Compound root with all standard and layered parts. |
CardRoot | Named outer surface export. |
CardHeader / CardTitle / CardDescription / CardAction | Named header composition exports. |
CardContent / CardFooter | Named body and footer exports. |
CardPrimary / CardSecondary | Named layered-surface exports. |
Card*Props / Card*Slots / CardSize | Public prop, slot, and size contracts. |
resolveCard* | Safe runtime resolvers for sizes and semantic elements. |