Card
Card is the white surface everything else sits on. It draws a rounded, padded, hairline-bordered box so the content inside reads as one panel against the page background — and nothing more: there are no header, footer, or title parts, you compose those yourself. Under the hood it is bg-white, rounded-2, p-4, and a border-secondary hairline.
ts
import { Card } from '@scaler-tech/aurora/card'Chrome states
Energy intensity
112
kWh/m² · portfolio average
<Card> — hairline border, no shadow
GHG intensity
24.6
kgCO₂e/m² · portfolio average
:border="false" — for nesting inside a bordered panel
Assets reporting
48 / 52
92% of gross floor area
shadow — lifted instead of outlined
Flush list shell
Highest intensity assets
2025
Nordhavn Office203 kWh/m²
Vesterbro Logistics164 kWh/m²
Islands Brygge 2487 kWh/m²
Use when
| Situation | Use | Why |
|---|---|---|
| Group related content into one panel | Card | that is the whole job |
| A row of KPI numbers above content | StatBar | it owns the band chrome; see Stat bar |
| A narrow centered section on a wide page | FocusPanel | it sets the measure, not the chrome |
| The full content of a page or tab panel | nothing | PageBody already sits on the page card — a wrapper Card double-frames it; see Page structure |
API
| Prop | Type | Default | Description |
|---|---|---|---|
border | boolean | true | Draws the border-secondary hairline. Pass :border="false" to drop it |
shadow | boolean | false | Swaps shadow-none for the legacy shadow-default lift |
class | string | — | Merged over the built-ins with twMerge, so a conflicting utility replaces the default rather than stacking — plain p-0 beats the built-in p-4, no ! needed |
Everything else — @click, id, data-*, role — falls through to the root <div>.
Example
vue
<Card>
<h3 class="heading-3-semibold">Energy intensity</h3>
<p class="paragraph-sm text-secondary">Portfolio average, last 12 months</p>
</Card>
<!-- nested inside an already-bordered container: drop the second hairline -->
<Card :border="false">…</Card>
<!-- list/table shell: flush, clipped to the radius -->
<Card class="p-0 overflow-hidden">
<Table … />
</Card>Incorrect / Correct
Incorrect (hand-rolled surface — the values drift the moment the token changes):
vue
<div class="bg-white rounded-2 border border-secondary p-4">
<h3 class="heading-3-semibold">Energy intensity</h3>
</div>Correct (one component owns background, radius, border, and padding):
vue
<Card>
<h3 class="heading-3-semibold">Energy intensity</h3>
</Card>Gotchas
borderdefaults totrue, so<Card border>does nothing. Reach for:border="false"whenever a card nests inside another bordered panel — otherwise you get two hairlines a few pixels apart.class="shadow-default"leaves the card flat —twMergedoesn't see the legacy name as conflicting with the built-inshadow-none. Use theshadowprop; for lift,hover:shadow-400.- The
shadowprop renders the legacy--shadow-default, notshadow-100…shadow-600— ashadowcard and ashadow-200sibling won't match. See Effects. - A clickable card isn't keyboard-reachable on its own —
Cardis a plain<div>with noasorhrefprop. Wrap it in a<RouterLink>or<button>instead of putting@clickon the card.
Related
- Page structure — where cards sit in the page column, and the flush list-shell recipe
- Effects — the
shadow-100…shadow-600elevation scale - Stat bar — the KPI band that owns its own chrome