Rules list
StableA numbered grid of short principles (01, 02, 03), each a title and one or two lines.
The few rules a tool follows, most important first: the number comes from the order. It is one column on phones, two from 640 pixels and three from 1024 (by the window, not the container). Each item arrives on scroll inside a page that calls useLuxe().
Three rules
import { Rules } from '@rchursin/product/shell/layout'
/** The Tasks tool's rules, most important first. Each is a [title, body] pair; the number comes from the order. */const rules: [string, string][] = [ ['Shape, never colour', 'Status is a square that fills up; priority is a meter of bars. Done and Canceled are both solid, so a tick or a cross tells them apart.'], ['One Tab stop, then arrows', 'The list is a grid: Tab lands once, arrows or J and K move, Enter opens. Fifty rows never cost fifty presses of Tab.'], ['Undo instead of “Are you sure?”', 'Changes happen at once and end in a toast with a single Undo. ⌘Z (Ctrl+Z) keeps working after the toast has gone.'],]
export default function RulesExample() { return <Rules items={rules} className="w-full" />}Usage
import { Rules } from '@rchursin/product/shell/layout'<Rules items={[['Shape, never colour', 'Status is a square that fills up.']]} />Examples
Arriving on scroll
Wrapped in a useLuxe() root, the items rise in one after another when motion is allowed.
import { useLuxe } from '@rchursin/components/motion'import { Rules } from '@rchursin/product/shell/layout'
const rules: [string, string][] = [ ['Start the week where the visitor does', 'Weeks begin on the locale’s first day: Sunday in the US, Monday in most of Europe. Home and End follow it too.'], ['Put the state in the label', 'Every date says what it is: “Today, Monday, October 12, 2026, selected”. Screen readers that skip aria-selected still hear it.'], ['Patterns, not colours', 'Team is solid, Focus hatched, Personal outlined, Releases dashed. Calendars stay apart in greyscale and in print.'],]
/** * Each item is a lux-reveal. Inside a root that calls useLuxe() they rise in one after another as * they scroll into view (only when motion is allowed); anywhere else they are simply there. */export default function RulesArrival() { const root = useLuxe<HTMLDivElement>() return ( <div ref={root} className="w-full"> <Rules items={rules} /> </div> )}API
Rules props
| Prop | Type | Default | Description |
|---|---|---|---|
itemsrequired | [string, string][] | – | Pairs of [title, body]. Titles must be unique (they are the React keys). |
className | string | – | Extra classes on the list. |
Accessibility
- An ordered list (<ol>), so screen readers hear how many rules there are and where they are. The 01, 02 is visible text inside each item as well.
- Each title is an <h3>; put the list under an <h2>.
- Items use lux-reveal: hidden only inside an armed useLuxe() root, and only when motion is allowed. With reduced motion they are simply there.
Guidelines
Do
- Keep it to three to six rules.
- Write titles as the rule itself (“Undo instead of ‘Are you sure?’”).
Don’t
- Don’t use it for steps someone must follow in order; that is a numbered procedure.
- Don’t write bodies longer than two lines at the widest column.
In use
Related
- Do and don’tA do / don’t pair: two cards side by side with a short note each, told apart by icon, word and a dashed edge.
- Key tableKeyboard shortcuts as a two-column table: key caps on the left, what they do on the right.
- SectionA page band with an eyebrow, an h2 and a lead, on a plain or sunken ground. SectionHeading is the heading block alone.
- Scroll arrivalsContent that fades and rises in as it scrolls into view, bars that grow, stamps that land and a frame that draws itself.
Source
The component’s own files, exactly as they run on this site.
/** * Layout pieces for the kit pages: an intro, numbered sections, specimens (one component on a * card with a caption), a keyboard table and a short list of rules. * They share the site's finishing layer: arrivals (lux-reveal), hairlines, grain, the halo. */import type { ReactNode } from "react"import { cx } from "../../components/cx"import { useLuxe } from "../../components/motion"import { delay } from "../../home/ui"import { KeyCombo } from "../ui/button"
export function KitPage({ children, className }: { children: ReactNode; className?: string }) { const root = useLuxe<HTMLDivElement>() return ( <div ref={root} className={cx("bg-surface text-fg antialiased", className)}> {children} </div> )}