What a guest agrees to before they come, set out to be read: the arrival and departure times large, the house rules as a list where each answer is a word with a mark that repeats it in shape (a tick, a cross), what the stay includes, and the policies in a sentence or two each: cancelling, a deposit, a late arrival. Zero JavaScript.
Live demo
Before you come
Arrive from
15:00
Leave by
11:00
House rules
Pets
Welcome
Smoking
Outside only
Children
Welcome
Parties
Not allowed
Quiet hours
22:00 to 8:00
Included
Breakfast from 8 to 10
Towels and linen
Beach towels and an umbrella
Cancelling
Free up to 14 days before you arrive. After that, half the stay is due.
Arriving late
Tell us your time: the key waits in a box by the door.
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
tone
density
Measured
JavaScript of its own
0 B
Uses Reveal and the shared runtime (1.9 kB raw, once per site). With those included: 3.0 kB raw.
CSS 10.1 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Baseline · widely available
every browser. Elsewhere: nothing to fall back from.
Install Pro
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
terminal
npx shadcn@latest add @moonarc-pro/house-rules
src/pages/index.astro
---import HouseRules from '@/components/moonarc/pro/HouseRules.astro';---<HouseRules headline="Before you come" times={[{ label: 'Arrive from', value: '15:00' }, { label: 'Leave by', value: '11:00' }]} rules={[{ label: 'Pets', value: 'Welcome', allowed: true }, { label: 'Smoking', value: 'Outside only', allowed: false }]} included={{ label: 'Included', items: ['Breakfast', 'Towels and linen'] }} policies={[{ title: 'Cancelling', text: 'Free up to 14 days before you arrive; after that, half the stay.' }]}/>
Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: reveal.
Props
Prop
Type
Default
Description
headline
string
none
The heading. Slot "headline" wins and may hold an <em>.
eyebrow
string
none
A short line above the heading.
copy
string
none
A line under the heading.
times
{ label; value }[]
none
The arrival and departure, set large.
rules
{ label; value; allowed? }[]
none
The rules; allowed puts a tick or a cross before the value, which says it in words.
included
{ label; items: string[] }
none
What the stay includes.
policies
{ title; text }[]
none
The policies, a sentence or two each.
rulesLabel
string
'House rules'
The rules' heading.
level
1 | 2 | 3
2
Heading level of the heading; the parts are one below.
tone
'surface' | 'muted' | 'ink' | 'brand'
unset (paints nothing)
The section's ground.
density
'compact' | 'cozy' | 'roomy'
'cozy'
Block padding ×0.8 / ×1 / ×1.25 through --ma-density.
Theming and overrides
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
Nothing here moves but the Reveals, which hold still on their own.
With ClientRouter
CSS and Reveal.
Why it is built this way
Each rule's answer is a word; the tick or the cross before it is a mask in the text's colour, so it repeats the word in shape and never carries it alone.
The rules are a description list, so a screen reader reads each label with its answer.
A heading and lead beside a native accordion: one question open at a time, heights animated by the browser, keyboard and screen reader handled by <details>.
What a practice charges, as tables a reader can trust: one a group, each row a service, its price and a note, and where insurance applies a column that says in words whether it is covered, partly or not, with a mark that repeats it in shape.
every browserscroll
Around the house
Each bar is the time against the farthest place of its group.
On foot
The beachSand, and a café that opens at eight6 min
The harbourThe ferry to the islands, three a day12 min
What is around a place to stay, by how a guest gets there: a group a way (on foot, by bike, by car, by boat), each place a row with its name, a line about it and the minutes it takes, and a bar drawn to scale against the farthest place of its group, so the near ones read near at a glance.