Skip to main content

Card

Info:Layout
53

A surface container that groups related content, with optional header and footer regions.

surface container tile box panel

Live demo

live · @xtyle/astro

Card

Plain surface

The default card — a quiet panel that groups related content with no extra ceremony.

Interactive

hover me

Lifts on hover and grows a focus-within ring — for cards that behave as a single clickable target.

Compact

Tighter padding and inner spacing for dense, list-like layouts.

Action

click / Enter

The whole card is the button — click it, or Tab to it and press Enter or Space. Activated 0 times.

With header & footer

Cards expose header, default, and footer slots. The body sits between two faintly ruled regions, so a title and an action row frame the content without any manual dividers.

Success:stable Info:v1 surface

Depth — how far it lifts

Set depthStrength to tune the shadow: sm is a whisper, md the eased default, lg a pronounced lift.

sm — whisper
md — default
lg — pronounced

Toned — a leading accent bar

Set tone to mark a card with a colored edge; leave it off for the plain neutral surface.

Accents

accent
accent-2
accent-3
accent-4
neutral

Statuses

success
info
warn
danger

Named hues

red
orange
yellow
green
blue
purple
brown
pink
cyan
gray
white
black

Overlay surface

The translucent variant for cards that float over content — popovers, menus, command palettes.

Card is the workhorse surface: a bordered, elevated panel that frames related content as one unit. It lays its three regions (header, body, footer) out in a column with consistent spacing; the header and footer are real light-DOM parts (.xtyle-card__header / .xtyle-card__footer), so the same structure renders identically across every binding.

An overlay variant swaps the surface for the translucent treatment used inside popovers and menus; a compact size tightens the padding; an interactive variant adds a hover elevation lift plus a focus-within ring for cards that act as a single clickable target. That last one is presentational only: it styles the surface but adds no behavior, so the consumer wraps the clickable content in a real <button> or <a> for keyboard and screen-reader semantics.

When to use

How this component composes with the rest of the set.

Use Card as the frame for any grouped content: forms, media, summaries, list items.
For a card whose content carries its own control, set interactive and wrap that content in a real <button> or <a>; the variant supplies the hover/focus affordance but no behavior.
For a card that is itself one clickable target running a JS action, set action instead: the card becomes a keyboard-operable button (role="button", tab stop, Enter/Space), so an onclick on it works for the keyboard with nothing to wrap.
Pair the overlay variant with floating surfaces (popovers, menus, toasts) so the card matches their translucent treatment.

Props

6 props, straight from the manifest.

PropTypeDefaultBindingsDescription
overlay boolean false
html svelte astro
The translucent overlay surface, for cards floating over content (popovers, menus).
interactive boolean false
html svelte astro
Adds a hover elevation lift and a focus-within ring for cards that act as a single clickable target. Presentational only: it adds no role or tab stop, so wrap the clickable content in a real button or link (or use `action` when the card itself is the button).
action boolean false
html svelte astro
Makes the card itself the button: it takes `role="button"`, a tab stop, and Enter/Space activation, so a JS `onclick` on the card is keyboard-reachable with no inner control. Implies the interactive hover lift, and its focus ring shows on keyboard entry only. Use it for a card that runs an action (open this item, select this row); for a card that navigates, use a link inside or `CardLink`. Do not put another interactive element inside an `action` card.
compact boolean false
html svelte astro
Tightens the padding and inner spacing for dense layouts.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
html svelte astro
Adds a leading-edge accent bar in the chosen tone (any semantic role, accent variant, or named hue). Omit it for the plain neutral surface.
depthStrength "sm" | "md" | "lg"
sm md lg
md
html svelte astro
How far the surface lifts off the page: `sm` is a whisper, `md` (the default) an eased shadow, `lg` a pronounced lift. An interactive card bumps one step heavier on hover.

Appearance

Variants

default

.xtyle-card

The standard elevated surface on the raised background.

overlay

.xtyle-card--overlay

The translucent overlay surface, for cards floating over other content.

interactive

.xtyle-card--interactive

Hover elevation lift plus a focus-within ring for a clickable card.

Sizes

default

default
.xtyle-card

Standard padding.

compact

.xtyle-card--compact

Tightened padding and spacing.

States

hover

.xtyle-card--interactive:hover

Pointer over an interactive card; the surface lifts and the overlay paints the hover tint.

active

.xtyle-card--interactive:active

Interactive card pressed; the lift drops and the overlay paints the press tint.

focus-within

.xtyle-card--interactive:focus-within

Keyboard focus lands inside an interactive card: a token-colored ring, plus a transparent outline that becomes real in forced-colors mode.

Anatomy

The named parts that make up the component, with their selectors.

card

.xtyle-card

The surface container carrying the variant and size classes.

--font-sans --text-body --leading-normal --fg-0 --bg-1 --border-thin --line --radius-lg --elevation-1 --space-5 --space-4

header

.xtyle-card__header

The top region, a heading-weight title for the card.

--text-lg --weight-semibold --leading-tight --fg-0

body

.xtyle-card__body

The main content region.

--fg-1

footer

.xtyle-card__footer

The bottom region: separated by a top border, drawn in muted ink.

--space-3 --border-thin --line --fg-2

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 53/53 consumed tokens produced default register: 299 tokens

Live coverage check against the xtyle-default register (derive(xtyleDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --accent-2 --accent-3 --accent-4 --bg-1 --black --blue --border-normal --border-thick --border-thin --brown --cyan --danger --duration-fast --ease-standard --elevation-0 --elevation-1 --elevation-2 --elevation-3 --fg-0 --fg-1 --fg-2 --font-sans --gray --green --info --leading-normal --leading-tight --line --line-2 --neutral --orange --pink --purple --radius-lg --red --ring --space-1 --space-2 --space-3 --space-4 --space-5 --state-hover --state-press --success --surface-overlay --surface-overlay-border --text-body --text-lg --warn --weight-semibold --white --yellow

Slots

default
html svelte astro

The card body content.

header
html svelte astro

The card title region, rendered above the body.

footer
html svelte astro

The card footer region, rendered below the body with a top border.

Accessibility

Card is a plain surface container with no implicit role; put semantic elements (headings, lists, buttons) inside it.
The interactive variant is presentational only: it adds no role or tab stop. Wrap the clickable target in a native <button> or <a> so keyboard and screen-reader semantics come for free.
The action variant makes the card itself the button: it reflects role="button", takes a tabindex tab stop, and maps Enter/Space to the same activation a click fires. Do not nest another interactive element inside an action card; a button must not contain a button or link.
An interactive card rings on :focus-within (the real control inside it takes focus); an action card rings on :focus-visible, so a pointer click never paints the ring but keyboard entry does.
Focus is shown with a token ring and a transparent outline that the forced-colors base rule promotes to a real system outline.

Code

Regions and variants

Header, body, and footer regions; the overlay, compact, and interactive variants.

<xtyle-card>
	<h3 slot="header">Monthly report</h3>
	<p>Revenue is up 12% over last month, driven by the new onboarding flow.</p>
	<div slot="footer">Updated 2 hours ago</div>
</xtyle-card>

<xtyle-card overlay compact>
	<p>A compact card on a translucent overlay surface.</p>
</xtyle-card>

<xtyle-card interactive>
	<h3 slot="header">Pricing</h3>
	<p>See every plan and what is included.</p>
	<a slot="footer" href="/pricing">View plans</a>
</xtyle-card>
<script lang="ts">
	import { Card } from "@xtyle/svelte";
</script>

<Card>
	{#snippet header()}<h3>Monthly report</h3>{/snippet}
	<p>Revenue is up 12% over last month, driven by the new onboarding flow.</p>
	{#snippet footer()}Updated 2 hours ago{/snippet}
</Card>

<Card overlay compact>
	<p>A compact card on a translucent overlay surface.</p>
</Card>

<Card interactive>
	{#snippet header()}<h3>Pricing</h3>{/snippet}
	<p>See every plan and what is included.</p>
	{#snippet footer()}<a href="/pricing">View plans</a>{/snippet}
</Card>
---
import { Card } from "@xtyle/astro";
---

<Card>
	<h3 slot="header">Monthly report</h3>
	<p>Revenue is up 12% over last month, driven by the new onboarding flow.</p>
	<div slot="footer">Updated 2 hours ago</div>
</Card>

<Card overlay compact>
	<p>A compact card on a translucent overlay surface.</p>
</Card>

<Card interactive>
	<h3 slot="header">Pricing</h3>
	<p>See every plan and what is included.</p>
	<a slot="footer" href="/pricing">View plans</a>
</Card>

Action card

An action card is itself a keyboard-operable button: it focuses, Enter and Space fire its onclick, and the ring shows on keyboard entry only.

<xtyle-card action onclick="openProject('atlas')">
	<h3 slot="header">Atlas</h3>
	<p>Last edited 2 hours ago.</p>
</xtyle-card>
<script lang="ts">
	import { Card } from "@xtyle/svelte";
	let { openProject }: { openProject: (id: string) => void } = $props();
</script>

<Card action onclick={() => openProject("atlas")}>
	{#snippet header()}<h3>Atlas</h3>{/snippet}
	<p>Last edited 2 hours ago.</p>
</Card>
---
import { Card } from "@xtyle/astro";
---

<Card action onclick="openProject('atlas')">
	<h3 slot="header">Atlas</h3>
	<p>Last edited 2 hours ago.</p>
</Card>