Skip to content

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 ​

SituationUseWhy
Group related content into one panelCardthat is the whole job
A row of KPI numbers above contentStatBarit owns the band chrome; see Stat bar
A narrow centered section on a wide pageFocusPanelit sets the measure, not the chrome
The full content of a page or tab panelnothingPageBody already sits on the page card — a wrapper Card double-frames it; see Page structure

API ​

PropTypeDefaultDescription
borderbooleantrueDraws the border-secondary hairline. Pass :border="false" to drop it
shadowbooleanfalseSwaps shadow-none for the legacy shadow-default lift
classstring—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 ​

  • border defaults to true, 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 — twMerge doesn't see the legacy name as conflicting with the built-in shadow-none. Use the shadow prop; for lift, hover:shadow-400.
  • The shadow prop renders the legacy --shadow-default, not shadow-100…shadow-600 — a shadow card and a shadow-200 sibling won't match. See Effects.
  • A clickable card isn't keyboard-reachable on its own — Card is a plain <div> with no as or href prop. Wrap it in a <RouterLink> or <button> instead of putting @click on the card.
  • Page structure — where cards sit in the page column, and the flush list-shell recipe
  • Effects — the shadow-100…shadow-600 elevation scale
  • Stat bar — the KPI band that owns its own chrome