Dovetail — authoring rules (always apply)
Dovetail is white-label. Nothing in it may know a brand.
Tokens
- Never write a literal value. No hex, no px, no ms, no cubic-bezier. Every colour, dimension, radius, shadow, and duration is
var(--dt-*). If the value you need does not exist, add a token first — at the correct tier — then use it. - Respect the tier direction: component → semantic → primitive. Components and product code read semantic tokens. Only
--dt-viz-*chart code may read a primitive, and it must say why in a comment. - Never put a value word in a semantic or component token name. No
surface-blue, nobutton-purple-bg. Colour names live in Tier 1 only. - Use background and foreground roles as pairs.
--dt-surface-actionwith--dt-text-on-action. Never mix a surface from one pair with text from another. - All spacing is 4px-based, from
--dt-space-*.--dt-dim-hairand--dt-dim-hair-2are for borders and optical nudges only — never layout.
Type
- Apply a complete type role, not a loose font size: family, size, line-height, weight, and tracking from the same
--dt-text-<role>-*set. - Sentence case everywhere — headings, buttons, labels, table headers. The eyebrow role is the only thing ever uppercased.
Components
- Compose from
components/. Never re-implement Button, Input, Card, or any other primitive inside a screen or template. - Every new component ships four files:
Name.jsx,Name.d.ts(props contract),Name.md(agent-facing guidelines), and an entry in its directory's@dsCardHTML. - Accessible labels are required props, not optional. An icon-only control without a label is a bug, not a style choice.
- Components take content as props. No hard-coded copy, no fetching, no CMS coupling. A component must render identically from React state, Sanity, or a JSON file.
Visual
- One primary action per view. Everything else is secondary, ghost, or a link.
- Backgrounds are flat. No gradients, textures, or patterns. Depth comes from
--dt-elevation-*and surface hierarchy. - Elevation is a level, not a shadow you picked. Use
--dt-elevation-0through5. - Focus rings are system-owned.
:focus-visiblewith--dt-focus-ring-*. Never remove one, never restyle one per component. - Motion uses a
--dt-motion-*role. 100–300ms. No bounces, no infinite loops, no motion that is purely decorative. - Icons are Lucide, 2px stroke, sized from
--dt-size-icon-*, colouredcurrentColor. No emoji, no unicode glyphs, no hand-drawn SVG illustration.
Writing
- Confident and educational. State the rule, then the reason. Second person, active voice, present tense. Name tradeoffs instead of hiding them.
- No emoji, no exclamation points, no hype adjectives. Nothing is powerful, seamless, or delightful.
- Buttons are verb-first, one to three words. Errors say what happened and what to do next.
Before you ship
- Verify in light and dark, and under at least one demo theme. If it only works in the default theme, it is not finished.
- Self-audit against the Rules checklist in
readme.md.