Design System

Portal card

The canonical Halwel dashboard tile. 560px wide, brand-card surface, the same shape every patient card composes — dosage tracker, weight trends, prescription vials, symptoms log.

The body slot is a free region. When no children are passed, renders a blank-state placeholder so the shape is visible and the same component doubles as a real loading state.

Header slot accepts actions (right-aligned icon buttons via PortalCardIconButton); footer accepts a primary action (the + Log new dose pattern).

import from @halwel/ui/components/dashboard/PortalCard

Variants

Blank — primary variant

No title, no children. The shape itself: 560×720, brand-card blue, 18px shadow.

With title only

Weight trends

The minimum semantic state. Just a card with a name.

With title + meta

Dosage tracker

Updated 12m ago

Meta is a small uppercase line — used for timestamps, secondary IDs, etc.

With header actions

Dosage tracker

Actions slot — typically two placeholder buttons + one live (chart↔list toggle).

With subtext

GLP-1 dosage tracker

Semaglutide · 0.5 mg

Subtext sits between header and body — typically the medication line on a primary card.

With footer action

Weight trends

the "+" leads by default; pass showPlus={false} for non-add actions.

Footer action — success state

Weight trends

Gold tint after a successful log. Flips back to default on next render.

Footer action — disabled

Dosage tracker

Fully composed (mock body)

GLP-1 dosage tracker

Wk 4 of 12

Semaglutide · 0.5 mg

Body content slot — real cards put their chart, list, or metric strip here.

What a real patient card looks like end-to-end — title, meta, actions, subtext, body content, footer action.

Prescription variant

Ozempic

Rx · 4 refills

560px tall, slimmer padding. The patient app's vial cards.

Compact variant

Next refill

Ships Dec 14 · arriving by Dec 16

215px floor; for single-metric cards or short status tiles.

Fluid (fills container)

Care team

Dr. J. Okafor · Dr. M. Liang

Drop the fixed 560px width when the card sits in a column that already constrains width.

actionsFallback — default placeholder header buttons

Dosage tracker

Opt-in: when actions is omitted, render N placeholder icon-buttons so cards stay visually aligned even when actions aren't wired up.

reserveFooter — keep card geometry when no footer action

Dosage tracker

Opt-in: render an invisible spacer of footer height so card bodies in a column align at the bottom edge.