-
Notifications
You must be signed in to change notification settings - Fork 19
Open
Description
Interactions
- Match visual and hit targets
- Exception: The visual target is small (less then 32px). Hit target should be at least 32px.
- All flows work via keyboard
- Every focusable element has a focus ring
- Add
aria-label
when needed. Check the accessibility tree. This is important for humans/agents/llms/ai/everyone. <Input>
s font size needs to be at least 16px for mobile. This prevents iOS Safari from zooming/panning the page when an input is focused.- Buttons with loading states should show a loading indicator and the original label
- Prefer to persist application state to the URL. This makes sharing, linking, refreshing, backwards/forward navigation just work.
- Optimistic updates when possible
- Menu options that require additional user input should end with ellipsis to signify that
- Focus is managed correctly
- Destructive operations have a confirmation
Animations
- Have a
prefers-reduced-motion
variant - Prefer implementing with CSS, avoid main thread animations
- Preference stack
- CSS
- Web Animations API
motion
- Preference stack
- Prioritize GPU-accelerated animations, doesn’t cause reflows/repaints
- Be critical on whether an animation/transition is needed
- Easing curves depend on the thing that’s animating
Layout
- Optically aligned depending on the lockup. ±1px is ok.
- Contrast sometimes need to be balanced too depending on the lockup
- Everything should be aligned with something else on the page
- Make sure it works on different screen sizes (mobile, laptop, ultra-wide)
- Testing ultra-wide: Zoom out to 50%
Content
- Use
<Tooltip>
only as a last resort prefering inline descriptions - Buttons with only icons need an
aria-label
- Skeletons mirror final content closely to prevent cumulative layout shift
- Page
<title>
reflects current context - No dead ends. Each screen should have a next step.
- Design and implement for empty, sparse, dense, and error states
- Prefer left/right quotes
- Limit text widows/orphans
Performance
Make sure to disable extensions and the Vercel Toolbar when testing performance. Extensions might add noise. The Vercel Toolbar has a known issue of adding forced reflow overhead.
- Test on iOS low power mode and on MacOS Safari
- Inspect rerenders (React DevTools or React Scan)
- Profile with throttled CPU
- Test with throttled network
- Minimize reflows/repaints
POST/PATCH/DELETE
complete in under 500ms
Forms
- Enter submits when an input is focused
- In
<textarea>
⌘/Ctrl+Enter submits, Enter adds newline - Links should be
<a>
. ⌘/Ctrl+Click, middle click, right click → open a new tab, link affordances should work - Every control has a
<label>
, clicking it focuses the control - Clicking a
<label>
should make the associated control active - Keep submit enabled until submission starts; then disable during in-flight + show spinner + idempotency key. (Prevents double-submit while preserving the “let me try” principle.)
- Submit buttons should never be disabled. Let the user submit an incomplete form as a feedback mechanism.
- Checkboxes/radios should not have dead zones
- Errors should appear as close to the originating thing as possible. For example input validation errors should be next to the input that’s causing the error, not at the top or bottom of the form.
<input>
s should setautocomplete
when possible. This makes it easier for people to fill out forms.- Some
<input>
s should disablespellcheck
<input>
s should have the correcttype
andinputmode
- Form field placeholders should end with an ellipsis as an additional signifier that the input has no value
Metrics
- Business metrics are measured and are accurate
Copywriting
- Headings & buttons: Title Case.
- Keep it clear and concise, use as few words as possible
- Action-oriented language
- Instead of "You will need the CLI…" say "Install the CLI…"
- Use consistent nouns and introduce as few nouns as possible
- Use numerals for numbers
- “8 deployments” instead of “eight deployments”
- Use
tabular-nums
or Geist Mono when it’s important to compare numbers - Default to positive language
- Frame messages in an encouraging, problem-solving way, even for errors.
- Example: Instead of "Your deployment failed," say "Something went wrong—try again or contact support."
- Error messages should guide users how to exit error state
- Don’t just state what went wrong—tell them how to fix it.
- Example: Instead of "Invalid API key," say "Your API key is incorrect or expired. Generate a new key in your account settings." The copy and button/links help educate and give the user an action.
Metadata
Metadata
Assignees
Labels
No labels