Status: Living guidance
Last reviewed: 2026-07-14
Canonical source: This Markdown file
Derived companion: native-first-prototype-handbook.html
This handbook is a starting point, not a rigid framework. Prefer semantic HTML, resilient CSS, and narrowly justified JavaScript. Keep the page useful when scripts fail, are blocked, or have not loaded yet.
1. Purpose#
This handbook reconciles our working guidance for:
- Native HTML and CSS before JavaScript
- Mobile-first and responsive design
- Progressive disclosure
- Dashboards, modular blocks, sidebars, sticky headers, and complex data
- Modern CSS architecture and feature detection
- Tables, data grids, sticky rows and columns, highlighting, and merged cells
- Drag, drop, ordering, dashboard placement, and free-form layouts
- Print CSS
- Modern CSS reset and starter layers
- HTML/CSS comments for human and LLM takeover
- Accessibility, security, performance, and compatibility
The goal is not “zero JavaScript.”
The goal is:
Server- or document-rendered content first, CSS-owned presentation second, and the minimum JavaScript needed for state, data, focus, or complex interaction.
A prototype should normally show meaningful content immediately, even when JavaScript is disabled.
2. Core design principles#
2.1 Progressive enhancement#
Build in this order:
- Semantic HTML
- CSS layout and presentation
- Native browser behavior
- Server navigation and form submission
- Small JavaScript enhancement
- Full client-side state only when justified
Baseline content must not depend on hydration.
2.2 Meaning before layout#
- Use HTML to define what the content is.
- Use CSS to define how it is arranged.
- Use JavaScript to manage state and behavior.
- Use the server to enforce authorization and data integrity.
2.3 One useful page without JavaScript#
A generated prototype should normally:
- Render headings, text, tables, forms, and navigation without JavaScript.
- Use real links.
- Use real form actions.
- Avoid an empty root element waiting for client rendering.
- Avoid hiding the entire page until initialization.
- Avoid requiring JavaScript for first paint.
2.4 Capability, not ideology#
Use JavaScript when it improves or enables:
- Asynchronous data
- Optimistic updates
- Persistent client state
- Complex focus management
- Tabs, comboboxes, trees, grids, and other composite widgets
- Drag and drop
- Virtualization
- Live updates
- Cross-component coordination
- Dynamic announcements
- Geometry and collision detection
3. Ownership model#
| Concern | Preferred owner |
|---|---|
| Document meaning | HTML |
| Reading order | DOM |
| Navigation | Links and forms |
| Baseline disclosure | <details> and <summary> |
| Modal surface | <dialog> |
| Layout | CSS |
| Responsive adaptation | CSS media/container queries |
| Visual state | CSS selectors and custom properties |
| Application state | JavaScript or server |
| Authorization | Server |
| Validation | HTML first, server authoritative |
| Async data | JavaScript |
| Persistence | Server or storage through JavaScript |
| Print redaction | Server |
| Print presentation | CSS |
| Drag coordinates/order | JavaScript |
| Canonical order | Data model and DOM |
4. Default page architecture#
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Prototype</title>
<link rel="stylesheet" href="/styles/index.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<header class="site-header">
<a href="/" class="brand">Product</a>
</header>
<div class="app-shell">
<nav class="primary-navigation" aria-label="Primary">
<ul role="list">
<li><a href="/overview" aria-current="page">Overview</a></li>
<li><a href="/activity">Activity</a></li>
<li><a href="/settings">Settings</a></li>
</ul>
</nav>
<main id="main-content" tabindex="-1">
<h1>Overview</h1>
<p>Meaningful content is visible before JavaScript runs.</p>
</main>
</div>
</body>
</html>
Rules#
- Use one
<main>. - Use
<nav>for navigation, even when visually positioned as a sidebar. - Use
<aside>only for complementary content. - Use source order that remains meaningful at every breakpoint.
- Use one primary page scrolling surface by default.
5. Native HTML before JavaScript#
5.1 Disclosure#
<details>
<summary>Advanced settings</summary>
<p>Secondary content.</p>
</details>
Use for:
- FAQs
- Optional explanations
- Advanced settings
- Secondary metadata
- Simple navigation groups
Use independent disclosures by default. Add a shared name only when one-open-at-a-time behavior is explicitly required.
5.2 Dialog#
Use <dialog> for a modal surface. A small script to call showModal() is justified.
<button type="button" data-open-dialog="delete-dialog">
Delete project
</button>
<dialog id="delete-dialog" aria-labelledby="delete-title">
<form method="dialog">
<h2 id="delete-title">Delete project?</h2>
<p>This cannot be undone.</p>
<button value="cancel" autofocus>Cancel</button>
<button value="confirm">Delete</button>
</form>
</dialog>
document.addEventListener("click", (event) => {
const trigger = event.target.closest("[data-open-dialog]");
if (!(trigger instanceof HTMLButtonElement)) return;
const dialog = document.getElementById(trigger.dataset.openDialog ?? "");
if (dialog instanceof HTMLDialogElement) {
dialog.showModal();
}
});
5.3 Forms#
Use native constraints first:
<form action="/accounts" method="post">
<label>
Work email
<input type="email" name="email" autocomplete="email" required>
</label>
<button type="submit">Create account</button>
</form>
Server validation remains authoritative.
5.4 Popovers#
Use popovers for non-modal contextual content only when the unsupported-browser result remains usable.
Do not automatically add role="menu" to a link list.
5.5 Responsive images#
<picture>
<source
media="(width >= 70rem)"
srcset="/images/dashboard-wide.avif"
type="image/avif">
<img
src="/images/dashboard-small.jpg"
alt="Dashboard overview"
width="800"
height="600"
loading="lazy">
</picture>
Do not lazy-load the likely LCP image.
6. When JavaScript is required#
Add JavaScript when any answer is yes:
- Does the interaction require business state?
- Must state survive navigation or reload?
- Must data be fetched without page navigation?
- Must state changes be announced dynamically?
- Does the widget require managed focus?
- Does it require arrow-key navigation or roving
tabindex? - Does it require asynchronous search or options?
- Does it coordinate several independent components?
- Does the target browser floor lack required native behavior?
- Would the fallback hide essential information?
- Does the action require rollback or error recovery?
- Must the state be audited or synchronized?
7. Responsive and mobile-first layout#
7.1 Start narrow#
.app-shell {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 1rem;
padding: 1rem;
}
@media (min-width: 64rem) {
.app-shell {
grid-template-columns:
minmax(14rem, 18rem)
minmax(0, 1fr);
align-items: start;
}
}
7.2 Use intrinsic layouts#
.dashboard-grid {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
gap: 1rem;
}
7.3 Media queries versus container queries#
- Media queries govern page-level adaptation.
- Container queries govern reusable component adaptation.
.dashboard-module {
container-type: inline-size;
}
@container (min-width: 36rem) {
.module-layout {
grid-template-columns: minmax(0, 2fr) minmax(12rem, 1fr);
}
}
7.4 Prevent intrinsic overflow#
.grid-child,
.flex-child {
min-inline-size: 0;
}
Use minmax(0, 1fr) for flexible content tracks that may contain tables, code, or long identifiers.
8. Tables, Flexbox, Grid, and normal flow#
| Requirement | Primitive |
|---|---|
| Sequential prose | Normal flow |
| One-dimensional control group | Flexbox |
| Two-dimensional layout | Grid |
| Shared nested alignment | Subgrid |
| Relational row/column data | <table> |
| Spreadsheet interaction | ARIA grid plus JavaScript |
Flexbox#
Best for:
- Toolbars
- Navigation clusters
- Button groups
- Avatar/text rows
- Wrapping tags
Prefer auto margins for group separation:
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.toolbar__end {
margin-inline-start: auto;
}
Grid#
Best for:
- App shells
- Dashboard modules
- Form alignment
- Repeating card layouts
- Two-dimensional composition
Tables#
Use tables when the intersection of a row and column is meaningful.
Do not convert native table elements to Grid or Flexbox merely to make them responsive.
Wrap wide tables in a named horizontal scroll region.
9. Alignment#
Default recommendations#
- Prefer logical
startandend. - Use
gapinstead of child margins. - Use baseline alignment for mixed typography.
- Use
safe centerwhere centering could clip. - Avoid
space-betweenfor unstable toolbars. - Avoid visual reordering that differs from DOM order.
- Treat
stretchas an explicit decision.
.metric-header {
display: flex;
align-items: baseline;
gap: 0.5rem;
}
10. Progressive disclosure#
Keep visible:
- Page purpose
- Current state
- Primary actions
- Errors
- Security warnings
- Required instructions
- Active scope
Good disclosure candidates:
- Advanced settings
- Secondary filters
- History
- Debug details
- Audit metadata
- Rare actions
Preferred escalation:
Visible content
→ details/summary
→ popover
→ non-modal dialog
→ modal dialog
→ scripted workflow
Do not hide important content merely because a container becomes narrow. Reflow before removing.
11. Sticky headers and scrolling#
11.1 Prefer document scrolling#
Avoid:
body {
overflow: hidden;
}
main {
height: 100vh;
overflow: auto;
}
unless the application truly requires an independent workspace.
11.2 Sticky header#
.site-header {
position: sticky;
inset-block-start: 0;
z-index: 20;
background: Canvas;
border-block-end: 1px solid;
}
html {
scroll-padding-block-start: 5rem;
}
:where(h1, h2, h3, h4, [id]) {
scroll-margin-block-start: 5rem;
}
Rules#
- Keep mobile sticky headers compact.
- Avoid stacked sticky bars.
- Do not auto-hide on scroll by default.
- Ensure focused elements are not obscured.
- Test at 200% and 400% zoom.
12. Sidebars and mobile navigation#
Start with navigation in normal flow.
At larger sizes, make it sticky:
@media (min-width: 64rem) {
.section-navigation {
position: sticky;
inset-block-start: 5rem;
}
}
For a true mobile drawer, use <dialog> plus minimal JavaScript.
Do not use checkbox-based CSS drawer hacks for application navigation.
13. Dashboards and modular blocks#
A dashboard module should have:
- One semantic root
- A descriptive heading
- Stable DOM order
- Useful no-JavaScript content
- A narrow-layout default
- Explicit loading, empty, error, restricted, and populated states
- Container-responsive styling when useful
Do not make every section a card.
Use cards for independently meaningful units. Use spacing, headings, and rules for ordinary document structure.
14. Data tables and complex data#
14.1 Semantic table#
<table>
<caption>Service health by region</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Availability</th>
<th scope="col">Latency</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">US East</th>
<td>99.98%</td>
<td>42 ms</td>
</tr>
</tbody>
</table>
14.2 Responsive table region#
<div
class="table-scroll"
role="region"
aria-labelledby="orders-heading"
tabindex="0">
<table>...</table>
</div>
.table-scroll {
max-inline-size: 100%;
overflow-x: auto;
}
14.3 Large data strategy#
Use in this order:
- Remove redundant columns.
- Shorten labels without losing meaning.
- Allow wrapping.
- Use a labeled scroll region.
- Add filtering and server pagination.
- Add a record-detail view.
- Add virtualization only after measuring a real need.
15. Sticky data grids#
Use one two-axis scroll container by default.
.data-grid-scroll {
position: relative;
isolation: isolate;
max-block-size: min(70svh, 48rem);
max-inline-size: 100%;
overflow: auto;
}
.data-table {
min-inline-size: max-content;
border-collapse: separate;
border-spacing: 0;
}
.data-table thead th {
position: sticky;
inset-block-start: 0;
z-index: 3;
background: Canvas;
}
.data-table tbody th[scope="row"] {
position: sticky;
inset-inline-start: 0;
z-index: 2;
background: Canvas;
}
.data-table thead th:first-child {
inset-inline-start: 0;
z-index: 4;
}
Sticky grid rules#
- Sticky cells need opaque backgrounds.
- Use explicit z-index layers.
- Prefer
border-collapse: separate. - Use logical inset properties.
- Use JavaScript for cumulative offsets when header heights or frozen-column widths are dynamic.
- Keep semantic table markup unless spreadsheet interaction is implemented.
16. Cell merging and highlighting#
Use rowspan and colspan only when data is semantically merged.
Avoid merged body cells in sortable, editable, virtualized, or reorderable grids.
For visual grouping, keep cells separate and layer backgrounds:
.data-table :is(th, td) {
--cell-base: Canvas;
--group-tint: transparent;
--row-tint: transparent;
--column-tint: transparent;
--selection-tint: transparent;
background:
linear-gradient(var(--selection-tint), var(--selection-tint)),
linear-gradient(var(--column-tint), var(--column-tint)),
linear-gradient(var(--row-tint), var(--row-tint)),
linear-gradient(var(--group-tint), var(--group-tint)),
var(--cell-base);
}
Do not rely on color alone. Add borders, focus rings, and text labels.
17. Drag, drop, ordering, and placement#
17.1 Choose the model first#
| Model | Stored state |
|---|---|
| Ordered list | Item sequence |
| Wrapped card grid | Item sequence |
| Dashboard grid | x, y, w, h |
| Bounded free-form surface | Pixel/world coordinates |
| Infinite canvas | World coordinates plus viewport transform |
| External file/data drop | DataTransfer payload |
17.2 Ordered content#
Store canonical order and render DOM in that order.
Do not use CSS order or transforms as permanent state.
Provide keyboard alternatives:
- Move up/down
- Move to start/end
- Move before/after another item
- Move to position
17.3 Dashboard grid#
Store logical coordinates and spans.
Define collision behavior:
- Push
- Swap
- Compact
- Free placement
Mobile should normally use semantic order rather than preserving desktop gaps.
17.4 Free movement#
Use Pointer Events and a dedicated drag handle.
- Capture the pointer.
- Use transforms for the preview.
- Commit model coordinates at drop.
- Batch movement with
requestAnimationFrame(). - Restrict
touch-action: noneto the handle. - Provide keyboard movement and coordinate entry.
17.5 Native HTML drag and drop#
Best for:
- Files
- URLs
- Text
- Cross-window or cross-application transfer
Not the default for touch-first in-app component movement.
17.6 Accessibility#
Every drag operation needs:
- A non-dragging pointer alternative
- A complete keyboard alternative
- Focus restoration
- Concise live-region announcements
- Adequate touch target sizes
Do not use deprecated aria-grabbed or aria-dropeffect.
18. Modern CSS state management#
Use the narrowest owner.
| State | Owner |
|---|---|
| Theme | <html> |
| Locale/direction | <html lang dir> |
| App density | Application root |
| Navigation expansion | Navigation shell |
| Module loading | Module |
| Field validity | Native control |
| Dialog open | Native dialog |
| Authorization | Server |
State channels:
- Native state:
open,checked,disabled,invalid - Semantic ARIA state
- Component
data-*state - Ancestor-derived state with
:has() - Downward propagation through custom properties
- JavaScript-owned application state
Use CSS for derived presentation, not business truth.
19. Feature detection#
Use fallback-first CSS.
.module {
display: block;
}
@supports (display: grid) {
.module {
display: grid;
}
}
Selector detection:
@supports selector(:has(*)) {
.field:has(:user-invalid) {
border-inline-start: 0.25rem solid;
}
}
JavaScript:
const supportsDialog =
"HTMLDialogElement" in window &&
"showModal" in HTMLDialogElement.prototype;
Do not use browser-name detection.
Compatibility tiers#
Tier A — default
- Semantic HTML
- Grid and Flexbox
- Media queries
- Logical properties
<details><dialog>with a small opening script- Sticky positioning
- Responsive images
- Native lazy loading
- Tables
- Reduced-motion queries
Tier B — progressive enhancement
- Container queries
:has()- Dynamic viewport units
- Popover
content-visibility- Scroll snap
scrollbar-gutter
Tier C — opt-in experimentation
- Advanced anchor positioning
- Scroll-state queries
- Scroll-driven animation
- Cross-document view transitions
- Customizable selects
- Generated scroll controls
Critical navigation, data access, form submission, and recovery must not depend on Tier C features.
20. iPhone input zoom#
iOS may zoom focused editable controls when their computed text size is too small. The observed threshold is approximately 16 CSS pixels.
Use:
:where(
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select,
textarea
) {
font: inherit;
font-size: max(1rem, 16px);
}
Keep labels and help text smaller if needed. Make controls compact through padding and line-height, not tiny editable text.
Do not disable user zoom.
Do not treat text-size-adjust, touch-action, or inputmode as fixes for focus zoom.
21. Print CSS#
Print should transform an application into a document.
21.1 Visibility utilities#
.print-only {
display: none;
}
@media print {
.print-hidden,
[data-print="exclude"] {
display: none !important;
}
.print-only {
display: block;
}
}
Use display: none, not visibility: hidden, for content removed from print.
Do not use the HTML hidden attribute merely for medium-specific visibility.
21.2 Security#
CSS hiding is not redaction.
Sensitive values must be omitted or masked before they reach the client.
Use a dedicated print route or server-generated PDF for authoritative, regulated, or privacy-sensitive documents.
21.3 Print palette#
@media print {
:root {
print-color-adjust: economy;
-webkit-print-color-adjust: economy;
}
body {
color: #000;
background: #fff;
}
.card {
background: transparent;
box-shadow: none;
border: 0.5pt solid #888;
}
}
Use exact selectively for small meaningful regions such as barcodes, QR codes, or essential chart keys.
Design for grayscale and photocopy degradation.
21.4 Print layout#
- Flatten app shells.
- Remove nested scrolling.
- Reset sticky and fixed positioning.
- Keep native tables.
- Use bounded
break-inside: avoid. - Prefer
size: autounless paper size is formal. - Do not rely on margin boxes for critical content.
- Test Chrome, Firefox, Safari, PDF, and physical printing.
22. Modern CSS reset#
Use a small reset, not a total erasure of browser defaults.
@layer reset {
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
tab-size: 4;
}
body {
margin: 0;
}
:where(
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd
) {
margin: 0;
}
:where(
ul[role="list"],
ol[role="list"]
) {
margin: 0;
padding: 0;
list-style: none;
}
:where(img, picture, video, canvas) {
display: block;
max-inline-size: 100%;
}
:where(img, video) {
block-size: auto;
}
svg {
max-inline-size: 100%;
}
:where(button, input, select, textarea) {
font: inherit;
color: inherit;
letter-spacing: inherit;
}
::file-selector-button {
font: inherit;
}
}
Do not put these in the reset:
appearance: none- Focus removal
- Global
all: unset - Global smooth scrolling
- Global animation destruction
- Font-smoothing directives
html { font-size: 62.5%; }- Universal text breaking
23. CSS starter architecture#
@layer
reset,
vendor,
tokens,
base,
layout,
components,
utilities,
overrides;
Suggested files:
styles/
├── index.css
├── reset.css
├── tokens.css
├── base.css
├── layout.css
├── components/
│ ├── button.css
│ ├── form-control.css
│ ├── dialog.css
│ └── table.css
└── utilities.css
Useful layout primitives:
.wrapper.flow.stack.cluster.auto-grid.sidebar-layout.scroll-region.visually-hidden
Keep the primitive set small.
24. HTML and CSS comments#
Comments preserve information the code cannot reliably reveal:
- Intent
- Contract
- Invariant
- Ownership
- Constraint
- Validation
- Exit condition
They should not narrate syntax.
Controlled vocabulary#
SECTIONCOMPONENTPURPOSECONTRACTINVARIANTSTATEA11YSECURITYPERFWORKAROUNDVALIDATETODOGENERATED
Example:
/* COMPONENT: data-grid
* OWNS: Sticky headers and selection presentation.
* DOES NOT OWN: Selection state or persistence.
* STATE OWNER: data-grid.ts
* VALIDATE: pnpm test:data-grid && pnpm test:visual
*/
HTML comments delivered to the browser are public. Do not include secrets, internal URLs, security bypasses, or customer data.
For complex components, prefer a local README with:
- Purpose
- Semantic baseline
- State ownership
- File map
- Validation commands
- Relevant ADRs
Use one canonical component name across HTML, CSS, JavaScript, tests, and docs.
25. Security defaults#
Links#
Open in the same tab by default.
When a new tab is required:
<a
href="https://external.example/"
target="_blank"
rel="noopener">
External documentation
</a>
Use noreferrer only when referrer suppression is intentional.
Do not treat nofollow, ugc, sponsored, or external as security controls.
Forms and state changes#
- Use POST or an appropriate mutation endpoint.
- Validate and authorize on the server.
- Use CSRF protection.
- Use defensive cookie settings.
- Confirm destructive actions.
- Use idempotency protection where duplicate submission matters.
DOM updates#
Prefer:
element.textContent = userValue;
container.append(document.createElement("li"));
Avoid unsanitized innerHTML, eval(), and javascript: URLs.
Production controls#
- Strict Content Security Policy
- Self-hosted assets where practical
- Subresource Integrity for immutable third-party CDN assets
- Restricted iframes with
title,sandbox,allow,loading, andreferrerpolicy
26. Accessibility baseline#
Target WCAG 2.2 AA.
Default requirements:
- Reflow at 320 CSS pixels
- Visible focus
- Focus not obscured by sticky content
- Minimum 24×24 CSS-pixel targets; approximately 44×44 preferred
- No keyboard traps
- No hover-only content
- No orientation lock unless essential
- No drag-only operation
- Descriptive headings and labels
- Meaningful source order
- Zoom remains enabled
- Reduced motion is respected
- Forced-colors support for critical states
- Non-color cues for status and selection
27. Performance baseline#
Generated prototypes should:
- Render meaningful server/static HTML.
- Avoid a blank client root.
- Include explicit image dimensions.
- Use responsive images.
- Avoid lazy-loading the likely LCP image.
- Minimize third-party scripts.
- Avoid hydrating static content.
- Paginate large datasets.
- Add virtualization only after measurement.
- Update existing DOM instead of rebuilding large HTML strings.
- Pause or reduce live refresh when hidden.
28. Portable design context and personalization#
The handbook defines semantic, behavioral, accessibility, security, performance, and compatibility guidance. It does not prescribe one visual identity.
Use DESIGN.md as the portable visual-context layer.
DESIGN.md should describe what the interface should look and feel like. It should not replace the actual component library, token source, implementation documentation, lint rules, or tests.
28.1 Precedence#
Apply decisions in this order:
- Legal, privacy, security, and server-authoritative requirements
- Accessibility and user-preference requirements
- Semantic HTML and resilient behavior from this handbook
- Product purpose, audience, content, and workflow
- Existing project components, tokens, and implementation standards
- Project
DESIGN.md - External visual references
- Starter-pack defaults
A visual reference may change color, type, spacing, shape, imagery, density, and component styling. It must not weaken semantics, keyboard behavior, focus visibility, contrast, responsive reflow, print output, security controls, or meaningful no-JavaScript content.
28.2 Context stack#
Use the smallest stack appropriate to the project.
Portable prototype
├── native-first-prototype-handbook.md
├── DESIGN.md
└── preview.html
Established project
├── AGENTS.md
├── native-first-prototype-handbook.md
├── DESIGN.md
├── design/
│ ├── components.md
│ ├── data-visualization.md
│ ├── content.md
│ └── accessibility.md
├── tokens/
├── component registry or Storybook
├── preview.html
└── lint and test configuration
Enterprise design system
├── All project context above
├── Existing component packages
├── Machine-readable component metadata
├── On-demand MCP, skill, or retrieval interface
├── Automated token and usage validation
└── Visual, accessibility, and browser test suites
The root DESIGN.md is a compact map and visual contract. Detailed component guidance should be loaded only when the component is relevant.
28.3 How the source ecosystem correlates#
| Source | Best role | What to take | What not to assume |
|---|---|---|---|
Google design.md specification |
Portable format authority | YAML front matter, rationale prose, lint/diff workflow | A complete production design-system implementation |
| Aura PaperFlow | Visual and layout exemplar | Modular paper-like composition, whitespace, restrained accent use, previewable DESIGN.md packaging | Authoritative product semantics, exact tokens, or licensed assets |
| Refero Styles | Analyzed visual-reference library | Palette, typography, spacing, component language, design rationale | Permission to clone source layouts, branding, copy, or proprietary fonts |
| Awesome DESIGN.md | Discovery and comparative corpus | Reusable document organization, do/don't patterns, preview conventions | That extracted brand files are current, official, complete, or appropriate to copy |
| Atlassian DESIGN.md research | Production operating guidance | Portability boundaries, context budgeting, component reuse, on-demand guidance, lint enforcement | That one internal benchmark generalizes to every model or project |
Use visual libraries as evidence and inspiration. Use the project’s implementation, tests, and product requirements as authority.
28.4 DESIGN.md format#
A portable DESIGN.md combines:
- YAML front matter containing compact machine-readable values
- Markdown prose explaining the design intent, restrictions, and application
---
name: Project visual system
description: Warm, information-dense operational interface
colors:
canvas: "#F7F5F0"
ink: "#181714"
accent: "#C95F32"
spacing:
sm: 0.5rem
md: 1rem
rounded:
sm: 0.375rem
md: 0.75rem
---
## Overview
A calm operational workspace that feels like a well-edited technical
notebook rather than a generic SaaS dashboard.
Token values provide precision. Prose provides the reasoning needed to apply those values coherently.
28.5 Specific references beat generic adjectives#
Avoid:
Modern, clean, premium, trustworthy.
Prefer:
A field engineer's technical notebook translated into an operational web
application: warm paper, dark ink, compact annotations, strong table rules,
and one restrained signal accent.
A specific material, publication, instrument, environment, or historical reference gives the generator constraints as well as visual direction.
28.6 Normalize references into semantic roles#
Do not bind components directly to source-specific names.
Translate references into semantic roles:
@layer tokens {
:root {
--surface-canvas: #f8f8f6;
--surface-raised: #ffffff;
--surface-subtle: #efeeeb;
--text-primary: #121212;
--text-secondary: #373734;
--text-muted: #6f6d68;
--border-subtle: #d7d5cf;
--accent-decorative: #d97757;
--action-primary-background: #121212;
--action-primary-foreground: #f8f8f6;
--focus-ring: #0b63ce;
--status-info: #225ea8;
--status-success: #176c3a;
--status-warning: #8a5200;
--status-danger: #a12b2b;
}
}
An external reference may use one decorative accent. The application may still require distinct focus, error, warning, success, and information roles.
28.7 Adapt, do not clone#
For each material reference, record:
| Decision | Meaning |
|---|---|
| Keep | Preserve the principle directly |
| Adapt | Translate it for product, accessibility, or platform needs |
| Reject | Do not use because it conflicts with requirements |
| Unknown | Validate before using |
Example:
| Reference characteristic | Decision | Application |
|---|---|---|
| Warm off-white canvas | Keep | Default light canvas |
| Modular paper-like sections | Adapt | Product-specific semantic modules |
| Small interface typography | Adapt | Preserve density while keeping editable controls approximately 16px or larger on iPhone |
| One orange or clay accent | Adapt | Decorative accent plus separate accessible functional colors |
| Minimal shadows | Keep | Prefer borders and surface contrast |
| Proprietary font | Reject unless licensed | Use a documented licensed or system fallback |
| Exact source layout or brand mark | Reject | Generate product-specific composition |
28.8 Root context must remain concise#
A single portable file is loaded all at once in many tools. As it grows, it increases latency, token consumption, context competition, and the risk that relevant details are truncated.
Keep the root file focused on:
- Visual intent
- Foundational roles
- High-value constraints
- Common component treatments
- Do's and don'ts
- References to deeper authoritative context
Move detailed material to:
design/
├── components/
│ ├── button.md
│ ├── data-grid.md
│ └── dialog.md
├── patterns/
│ ├── dashboard.md
│ └── forms.md
└── foundations/
├── accessibility.md
└── data-visualization.md
Use on-demand retrieval, skills, or MCP tools when the design system is too large to load efficiently as one document.
28.9 Existing components take precedence#
In an established application, DESIGN.md should tell agents to use the existing implementation rather than recreate it.
## Technical integration
Use the existing component package.
- Button: `@project/ui/button`
- Dialog: `@project/ui/dialog`
- Data table: `@project/ui/data-table`
Do not reimplement these components from token descriptions.
See `design/components.md` and Storybook for supported properties.
The visual file captures intent. The component library captures tested behavior and implementation.
Lint rules and tests should enforce:
- Approved components
- Deprecated token avoidance
- Accessible patterns
- Browser-support policy
- Styling boundaries
- No-JavaScript baseline requirements
28.10 Reference provenance and confidentiality#
Record for each reference:
- Source URL or file
- Date reviewed
- Official, community, or inferred status
- What was observed
- What was adapted
- Licensing or trademark constraints
- Whether it can be included in public prompts
Do not publish a portable design file containing:
- Confidential design-system internals
- Private component names
- Non-public roadmap information
- Proprietary asset URLs
- Customer-specific branding without authorization
- Security-relevant implementation details
Maintain a sanitized public or customer-uploadable variant when required.
28.11 Preview artifacts#
A design-context package should include a no-JavaScript visual fixture.
Recommended files:
DESIGN.md
preview.html
preview-dark.html # when dark mode exists
preview-print.html # when print is a product feature
reference-sources.md
The preview should demonstrate:
- Color roles
- Typography hierarchy
- Spacing
- Buttons
- Form controls
- Navigation
- Cards and sections
- Tables and data states
- Dialog/disclosure styling
- Focus and invalid states
- Long content
- Print behavior
The preview is a validation fixture, not a marketing page.
28.12 Machine validation#
Where compatible with the project, validate and compare portable design files:
npx @google/design.md lint DESIGN.md
npx @google/design.md diff DESIGN.md DESIGN.next.md
Also validate:
- WCAG contrast
- Font and asset licensing
- Broken token references
- Existing component import guidance
- Narrow and wide layouts
- JavaScript-disabled output
- Keyboard and focus behavior
- Reduced motion
- Forced colors
- Right-to-left text
- iPhone form focus
- Print and grayscale
- Visual regressions
28.13 Token interchange#
When structured token exchange is required, prefer a format aligned with the Design Tokens Community Group specification.
Recommended flow:
External reference or design library
→ observed or exported primitive tokens
→ portable DESIGN.md context
→ semantic project tokens
→ component tokens
→ existing components or HTML/CSS implementation
Do not bind application components directly to raw reference values when a semantic role can be used.
28.14 Prompting future generation#
Attach or reference:
native-first-prototype-handbook.md- Project
DESIGN.md - Relevant component guidance or registry, when available
Recommended instruction:
Use the handbook as behavioral and implementation guidance.
Use DESIGN.md as the portable visual-intent layer.
Use existing project components when they are available. Do not recreate
them from visual tokens. Load detailed component guidance only for the
components involved in this task.
Translate external references into semantic project tokens and
product-specific composition. Do not copy source branding, layouts, copy,
fonts, or assets.
Accessibility, security, compatibility, product requirements, print
requirements, and meaningful no-JavaScript content take precedence.
28.15 Validation questions#
Before accepting personalized output, ask:
- Does this feel intentionally specific rather than generically polished?
- Can the design be explained without listing only adjectives?
- Does it use existing components where available?
- Is important guidance in the root file, and detailed guidance retrievable on demand?
- Are source, licensing, and inference boundaries documented?
- Does the result remain usable without JavaScript?
- Does it pass accessibility, browser, security, and print checks?
- Is it product-specific rather than a clone of the reference?
29. Prototype generation checklist#
HTML#
<!doctype html>lang- charset
- viewport meta
- descriptive title
- skip link
- semantic landmarks
- real links and forms
- useful content before JavaScript
- no blank hydration shell
CSS#
- small reset
- explicit cascade layers
- narrow layout first
- intrinsic sizing
- logical properties
- visible
:focus-visible min-inline-size: 0- reduced-motion handling
- print styles
- no unnecessary experimental dependency
Forms#
- visible labels
- correct input types
autocomplete- native constraints
- server validation
- editable text at least approximately 16px on iOS
- no disabled user zoom
JavaScript#
- clear justification
- enhancement over baseline
- small ES modules
- no inline handlers
- safe DOM APIs
- focus management where required
- meaningful live announcements
- no permanent visual-only ordering state
Data#
- table semantics retained
- caption and headers
- labeled scroll region when needed
- server pagination before virtualization
- complete print/export path
Drag and drop#
- correct spatial model
- canonical data state
- dedicated handle
- keyboard alternative
- non-dragging pointer alternative
- focus restoration
- live-region result announcement
- server validation of persisted layout
Security#
rel="noopener"for new tabs- no secrets in HTML, comments, or
data-* - server authorization
- CSRF protection
- CSP
- no unsanitized HTML insertion
- iframe restrictions
- print hiding not treated as redaction
Validation#
- JavaScript disabled
- keyboard only
- narrow viewport
- browser zoom
- iOS Safari
- reduced motion
- forced colors
- right-to-left
- print preview
- physical or PDF print
- automated accessibility tests
- visual regression tests
30. Takeover and update workflow#
This file is the canonical source.
When new learning changes guidance:
- Update this Markdown file.
- Change the “Last reviewed” date.
- Add or update references.
- Regenerate the HTML companion.
- Note significant policy changes in a short changelog.
- Update code templates or examples that depend on the changed rule.
Recommended repository placement:
docs/
├── native-first-prototype-handbook.md
├── native-first-prototype-handbook.html
└── adr/
Recommended instruction in AGENTS.md:
Before generating or modifying prototype HTML/CSS, read:
`docs/native-first-prototype-handbook.md`.
Treat it as guidance, not a rigid framework. Preserve meaningful
no-JavaScript content unless the feature inherently requires scripting.
31. Reference index#
Use primary sources where possible.
HTML, CSS, and accessibility#
- MDN Web Docs: https://developer.mozilla.org/
- W3C Web Accessibility Initiative: https://www.w3.org/WAI/
- ARIA Authoring Practices Guide: https://www.w3.org/WAI/ARIA/apg/
- WCAG 2.2: https://www.w3.org/TR/WCAG22/
Compatibility and web platform#
- Web Platform Baseline: https://web.dev/baseline
- Web Platform Status: https://webstatus.dev/
- Can I Use: https://caniuse.com/
- WebKit Blog: https://webkit.org/blog/
- Chrome for Developers: https://developer.chrome.com/
Security#
- OWASP Cheat Sheet Series: https://cheatsheetseries.owasp.org/
- MDN Web Security: https://developer.mozilla.org/en-US/docs/Web/Security
Testing#
- Playwright: https://playwright.dev/
- axe-core: https://github.com/dequelabs/axe-core
- Stylelint: https://stylelint.io/
Portable design context and design systems#
- Google DESIGN.md specification: https://github.com/google-labs-code/design.md
- Google DESIGN.md philosophy: https://github.com/google-labs-code/design.md/blob/main/PHILOSOPHY.md
- Stitch DESIGN.md overview: https://stitch.withgoogle.com/docs/design-md/overview
- Atlassian DESIGN.md production research: https://www.atlassian.com/blog/how-we-build/atlassians-design-md-is-here-what-we-learned-testing-portable-design-context-in-practice
- Awesome DESIGN.md collection: https://github.com/VoltAgent/awesome-design-md/
- Aura PaperFlow visual/layout reference: https://www.aura.build/design-systems/paperflow-design-layout
- Refero Styles library: https://styles.refero.design/
- Refero Claude style reference: https://styles.refero.design/style/47cb86b6-cb2d-41c8-94ba-8607cd7c41cd
- Refero DESIGN.md examples: https://styles.refero.design/ai-agents/design-md-examples
- Design Tokens Community Group reports: https://www.designtokens.org/TR/2025.10/
- Design Tokens format specification: https://www.designtokens.org/TR/2025.10/format/
CSS architecture and resets#
- Normalize.css: https://github.com/necolas/normalize.css/
- modern-normalize: https://github.com/sindresorhus/modern-normalize
- A Modern CSS Reset: https://piccalil.li/blog/a-more-modern-css-reset/
- Josh Comeau CSS Reset: https://www.joshwcomeau.com/css/custom-css-reset/
Drag and layout systems#
- Pointer Events: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
- HTML Drag and Drop: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API
- Dnd Kit: https://github.com/clauderic/dnd-kit
- SortableJS: https://github.com/SortableJS/Sortable
- Interact.js: https://interactjs.io/
- GridStack: https://gridstackjs.com/
32. Changelog#
2026-07-14#
- Replaced the initial design-profile guidance with a portable
DESIGN.mdcontext stack informed by the Google format, Aura and Refero references, the Awesome DESIGN.md corpus, and Atlassian's production findings. - Added a design-reference and
DESIGN.mdpersonalization layer, including a Refero-derived example and semantic-token adaptation rules. - Initial reconciliation of native-first HTML/CSS guidance.
- Added mobile-first layout, progressive disclosure, data grids, drag/drop, print, reset, comments, security, and validation standards.
- Established Markdown as the canonical source and HTML as a derived companion.