15 components, one small kit. Each one is a single Astro file you can copy into a project. Nothing here needs a framework or a client bundle beyond a few lines of plain JS.

Every example below is the real component, rendered live. Props tables list what you can change; the snippet shows the usual call.

DemoBanner

A thin ink bar that marks a page as an unofficial draft. For sales demos only; remove it before a site goes live.

Entwurf von a2Studio – nicht die offizielle Website von Beispiel AG.
PropTypeDefaultWhat it does
businessstring—Name of the business the draft is for.
studiostring"a2Studio"Who made the draft.
<DemoBanner business="Ristorante Milano" />

Source: src/components/DemoBanner.astro

WritingIntro

Loading screen: a haze picture with the logo word written as if by hand, then the layer fades away (about 2.5 s). Pure CSS, skipped on later views in the same tab, plays to the end even when tapped, and left out entirely for reduced motion.

How it works: the script traces the centre line of each letter; the SVG masks the letter shape with those strokes and draws them in order.
PropTypeDefaultWhat it does
wordHandwriting—Data from src/data/handwriting/<word>.ts (letter shape plus pen strokes).
picturestring—Background picture, shown with object cover and grain.
durationnumber1.6Seconds for the pen to write the word.
inlinebooleanfalseRender in a 16:9 box instead of over the page (for previews like this one).
---
import WritingIntro from "../components/WritingIntro.astro";
import milano from "../data/handwriting/milano";
---
<WritingIntro word={milano} picture="/pictures/haze.webp" />

# new word: generate its data once
python scripts/handwriting.py fayrouz src/fonts/damion-latin-400-normal.woff2 \
  > src/data/handwriting/fayrouz.ts

Source: src/components/WritingIntro.astro

ExpandingMedia

Picture card that grows to full width as you scroll, after the anthropic.com hero. One variable drives the side inset, bottom inset and corner radius.

Scroll the page and watch the edges open.

PropTypeDefaultWhat it does
srcstring—Picture, cover-fitted behind the content.
width / heightnumber—Intrinsic size, to reserve space.
altstring""Leave empty when the picture is decoration.
tone"dark" | "light""dark"Text colour on the picture.
<ExpandingMedia src="/pictures/haze.webp" width={1600} height={686}>
  <Logo text="milano" size="xl" />
  <p>Terrasse mit 80 Plätzen.</p>
  <Button href="#karte">Speisekarte</Button>
</ExpandingMedia>

Source: src/components/ExpandingMedia.astro

Haze

The grainy gradient surface from pure CSS, under 1 KB. For bands, cards and empty states where a picture would be too heavy.

dawn
dusk
mist
paper
PropTypeDefaultWhat it does
variant"dawn" | "dusk" | "mist" | "paper""dawn"Colour mix.
driftbooleanfalseSlow 28 s drift; stops for reduced motion.
grainbooleantrueSVG noise on top.
asstring"div"Element to render.
<Haze variant="dusk" as="section" drift>…</Haze>

Source: src/components/Haze.astro

Button

One primary action per view; everything else secondary or ghost. A link when given href, otherwise a button. 10px corners.

PropTypeDefaultWhat it does
variant"primary" | "accent" | "secondary" | "ghost""primary"Visual weight.
size"sm" | "md" | "lg""md"Height 36 / 44 / 52 px.
hrefstring—Renders an a element.
type"button" | "submit" | "reset""button"For forms.
disabledbooleanfalseDimmed and not clickable.
<Button href="#karte">Speisekarte</Button>
<Button variant="secondary" size="sm">Replay</Button>

Source: src/components/Button.astro

Card

A quiet container with an optional media slot. 8px corners, so pictures inside keep their 4px.

Plain

A border and nothing else.

Raised

Soft shadow for things that float.

Haze

For one warm highlight.

PropTypeDefaultWhat it does
variant"plain" | "raised" | "haze""plain"Border only, soft shadow, or haze fill.
hrefstring—Makes the whole card a link.
<Card variant="raised" href="/journal/first">
  <img slot="media" src="/pictures/collage-compass.webp" width="900" height="1125" alt="…" />
  <h3>Title</h3>
  <p>One or two sentences.</p>
</Card>

Source: src/components/Card.astro

Badge

A small status or tag label. One word, sentence case.

Neutral New Open now Few seats Closed
PropTypeDefaultWhat it does
tone"neutral" | "clay" | "ok" | "warn" | "error""neutral"Colour.
dotbooleanfalseLeading status dot.
<Badge tone="ok" dot>Open now</Badge>

Source: src/components/Badge.astro

Callout

A short boxed message. Warn and error tones are announced as alerts.

Note

Plain information, no urgency.
PropTypeDefaultWhat it does
tone"note" | "clay" | "ok" | "warn" | "error""note"Colour and role.
titlestring—Bold first line.
<Callout tone="warn" title="Closed on 24 December">We open again on the 27th.</Callout>

Source: src/components/Callout.astro

Field

Label, control, hint and error in one, with the aria wiring done for you.

Please check the address.

PropTypeDefaultWhat it does
labelstring—Visible label.
namestring—Form name; also builds the id.
as"input" | "textarea" | "select""input"Control type.
type / placeholder / valuestring—Passed to the control.
hintstring—Help text under the control.
errorstring—Error text; marks the field invalid.
requiredbooleanfalseNative required.
<Field label="Email" name="email" type="email" hint="We only use it to confirm." required />

Source: src/components/Field.astro

HoursTable

Opening hours as a table. A three-line script marks today in Zurich time, so the highlight never goes stale.

Opening hours
Mondaytoday 11:30–14:00, 18:00–23:00
Tuesdaytoday 11:30–14:00, 18:00–23:00
Wednesdaytoday 11:30–14:00, 18:00–23:00
Thursdaytoday 11:30–14:00, 18:00–23:00
Fridaytoday 11:30–14:00, 18:00–24:00
Saturdaytoday 18:00–24:00
Sundaytoday closed

Sample data.

PropTypeDefaultWhat it does
hours{ day, open: string | null }[]—Seven rows, Monday first; null means closed.
notestring—One line under the table, such as kitchen hours.
labels{ caption, today, closed }GermanWords for the caption, today marker and closed days.
<HoursTable hours={hours} note="Kitchen until 22:00" labels={{ today: "today", closed: "closed" }} />

Source: src/components/HoursTable.astro