UX rules · 129

129 actionable UX/interface rules (ux-guidelines + web-interface merged), 93 of them with live good ✓ / bad ✗ demos — hover / click to feel the difference. Filter by category; the eight states and anti-patterns live on the Tune tab and in playbook 4.2 §3/§7.

Smooth Scroll

NavigationWeb▶ live demoHigh

Anchor links should scroll smoothly to target section

Section 1 — Getting started with the basics.

Section 2 — Configuration and options.

Section 3 — Troubleshooting and FAQ.

click §3

Section 1 — Getting started with the basics.

Section 2 — Configuration and options.

Section 3 — Troubleshooting and FAQ.

click §3

Do Use scroll-behavior: smooth on html element

Don't Jump directly without transition

Code examples
✓ html { scroll-behavior: smooth; }
✗ <a href='#section'> without CSS

Sticky Navigation

NavigationWeb▶ live demoMedium

Fixed nav should not obscure content

Acme Docs

Welcome aboard

Everything on this page starts below the bar, so nothing hides behind it.

Scroll and the bar sticks without stealing content.

scroll the page
Acme Docs

Welcome aboard

Everything on this page starts below the bar, so nothing hides behind it.

Scroll and the bar sticks without stealing content.

scroll the page

Do Add padding-top to body equal to nav height

Don't Let nav overlap first section content

Code examples
✓ pt-20 (if nav is h-20)
✗ No padding compensation

Active State

NavigationAll▶ live demoMedium

Current page/section should be visually indicated

Which page are you on?

click a tab

Which page are you on?

click a tab

Do Highlight active nav item with color/underline

Don't No visual feedback on current location

Code examples
✓ text-primary border-b-2
✗ All links same style

Back Button

NavigationMobileHigh

Users expect back to work predictably

Do Preserve navigation history properly

Don't Break browser/app back button behavior

Code examples
✓ history.pushState()
✗ location.replace()

Deep Linking

NavigationAllMedium

URLs should reflect current state for sharing

Do Update URL on state/view changes

Don't Static URLs for dynamic content

Code examples
✓ Use query params or hash
✗ Single URL for all states

Breadcrumbs

NavigationWeb▶ live demoLow

Show user location in site hierarchy

UltraBook 14

$1,299 · In stock

UltraBook 14

$1,299 · In stock

Three levels deep — no way back up the tree.

Do Use for sites with 3+ levels of depth

Don't Use for flat single-level sites

Code examples
✓ Home > Category > Product
✗ Only on deep nested pages

Excessive Motion

AnimationAll▶ live demoHigh

Too many animations cause distraction and motion sickness

New in v2.0

ThemesSearchExport

New in v2.0

ThemesSearchExport

Do Animate 1-2 key elements per view maximum

Don't Animate everything that moves

Code examples
✓ Single hero animation
✗ animate-bounce on 5+ elements

Duration Timing

AnimationAll▶ live demoMedium

Animations should feel responsive not sluggish

200ms — responds as you move

hover me

1200ms — still catching up

hover me

Do Use 150-300ms for micro-interactions

Don't Use animations longer than 500ms for UI

Code examples
✓ transition-all duration-200
✗ duration-1000

Reduced Motion

AnimationAllHigh

Respect user's motion preferences

Do Check prefers-reduced-motion media query

Don't Ignore accessibility motion settings

Code examples
✓ @media (prefers-reduced-motion: reduce)
✗ No motion query check

Loading States

AnimationAll▶ live demoHigh

Show feedback during async operations

Q3 report ready

Revenue up 12% quarter over quarter.

Q3 report ready

Revenue up 12% quarter over quarter.

Do Use skeleton screens or spinners

Don't Leave UI frozen with no feedback

Code examples
✓ animate-pulse skeleton
✗ Blank screen while loading

Hover vs Tap

AnimationAll▶ live demoHigh

Hover effects don't work on touch devices

Report.pdf
tap works
Report.pdf
hover to find it

Do Use click/tap for primary interactions

Don't Rely only on hover for important actions

Code examples
✓ onClick handler
✗ onMouseEnter only

Continuous Animation

AnimationAll▶ live demoMedium

Infinite animations are distracting

Uploading photos…

Motion = something is happening

Just decoration

Motion = nothing, forever

Do Use for loading indicators only

Don't Use for decorative elements

Code examples
✓ animate-spin on loader
✗ animate-bounce on icons

Transform Performance

AnimationWebMedium

Some CSS properties trigger expensive repaints

Do Use transform and opacity for animations

Don't Animate width/height/top/left properties

Code examples
✓ transform: translateY()
✗ top: 10px animation

Easing Functions

AnimationAll▶ live demoLow

Linear motion feels robotic

ease-out — arrives, then settles

hover me

linear — conveyor-belt motion

hover me

Do Use ease-out for entering ease-in for exiting

Don't Use linear for UI transitions

Code examples
✓ ease-out
✗ linear

Z-Index Management

LayoutWebHigh

Stacking context conflicts cause hidden elements

Do Define z-index scale system (10 20 30 50)

Don't Use arbitrary large z-index values

Code examples
✓ z-10 z-20 z-50
✗ z-[9999]

Overflow Hidden

LayoutWeb▶ live demoMedium

Hidden overflow can clip important content

By continuing you agree to the terms of service and our data policy.

scroll the box

By continuing you agree to the terms of service and our data policy.

where's the button?

Do Test all content fits within containers

Don't Blindly apply overflow-hidden

Code examples
✓ overflow-auto with scroll
✗ overflow-hidden truncating content

Fixed Positioning

LayoutWeb▶ live demoMedium

Fixed elements can overlap or be inaccessible

Inbox — 3 new messages

Drafts — 1 saved

Archive — all clear

We use cookies · OK
scroll the list

Inbox — 3 new messages

Drafts — 1 saved

Archive — all clear

We use cookies · OK
find the + button

Do Account for safe areas and other fixed elements

Don't Stack multiple fixed elements carelessly

Code examples
✓ Fixed nav + fixed bottom with gap
✗ Multiple overlapping fixed elements

Stacking Context

LayoutWeb▶ live demoMedium

New stacking contexts reset z-index

API key ⓘKeys rotate every 90 days. Copy before closing.
Billing settings
hover ⓘ
API key ⓘKeys rotate every 90 days. Copy before closing.
Billing settings
hover ⓘ

Do Understand what creates new stacking context

Don't Expect z-index to work across contexts

Code examples
✓ Parent with z-index isolates children
✗ z-index: 9999 not working

Content Jumping

LayoutWeb▶ live demoHigh

Layout shift when content loads is jarring

Sunset over the harbor

Shot on a rainy Tuesday.

Sunset over the harbor

Shot on a rainy Tuesday.

Do Reserve space for async content

Don't Let images/content push layout around

Code examples
✓ aspect-ratio or fixed height
✗ No dimensions on images

Viewport Units

LayoutWebMedium

100vh can be problematic on mobile browsers

Do Use dvh or account for mobile browser chrome

Don't Use 100vh for full-screen mobile layouts

Code examples
✓ min-h-dvh or min-h-screen
✗ h-screen on mobile

Container Width

LayoutWeb▶ live demoMedium

Content too wide is hard to read

Readable lines end after a comfortable measure, so your eye finds the next line without losing its place on the way back.

Readable lines end after a comfortable measure, so your eye finds the next line without losing its place on the way back. When text runs edge to edge across the whole container the return sweep gets longer and longer, rereads creep in, and the paragraph turns into a wall.

Do Limit max-width for text content (65-75ch)

Don't Let text span full viewport width

Code examples
✓ max-w-prose or max-w-3xl
✗ Full width paragraphs

Touch Target Size

TouchMobile▶ live demoHigh

Small buttons are hard to tap accurately

44×44px

try tapping

24×24px, 2px apart

try tapping

Do Minimum 44x44px touch targets

Don't Tiny clickable areas

Code examples
✓ min-h-[44px] min-w-[44px]
✗ w-6 h-6 buttons

Touch Spacing

TouchMobile▶ live demoMedium

Adjacent touch targets need adequate spacing

hover each target
hover each target

Do Minimum 8px gap between touch targets

Don't Tightly packed clickable elements

Code examples
✓ gap-2 between buttons
✗ gap-0 or gap-1

Gesture Conflicts

TouchMobile▶ live demoMedium

Custom gestures can conflict with system

Getting started guide
Keyboard shortcuts
Billing & invoices
Team permissions
API reference
Release notes
wheel-scroll me
Getting started
Shortcuts
Billing
Permissions
API
Releases
wheel-scroll me

Do Avoid horizontal swipe on main content

Don't Override system gestures

Code examples
✓ Vertical scroll primary
✗ Horizontal swipe carousel only

Tap Delay

TouchMobileMedium

300ms tap delay feels laggy

Do Use touch-action CSS or fastclick

Don't Default mobile tap handling

Code examples
✓ touch-action: manipulation
✗ No touch optimization

Pull to Refresh

TouchMobile▶ live demoLow

Accidental refresh is frustrating

New comment on your post
Build #214 passed
Weekly digest is ready
Password changed
Invoice paid
Storage at 80%
scroll past the end
New comment on your post
Build #214 passed
Weekly digest is ready
Password changed
Invoice paid
Storage at 80%
scroll past the end — page jumps

Do Disable where not needed

Don't Enable by default everywhere

Code examples
✓ overscroll-behavior: contain
✗ Default overscroll

Haptic Feedback

TouchMobileLow

Tactile feedback improves interaction feel

Do Use for confirmations and important actions

Don't Overuse vibration feedback

Code examples
✓ navigator.vibrate(10)
✗ Vibrate on every tap

Focus States

InteractionAll▶ live demoHigh

Keyboard users need visible focus indicators

tab into this
tab into this — where is focus?

Do Use visible focus rings on interactive elements

Don't Remove focus outline without replacement

Code examples
✓ focus:ring-2 focus:ring-blue-500
✗ outline-none without alternative

Hover States

InteractionWeb▶ live demoMedium

Visual feedback on interactive elements

hover me
hover me — is it clickable?

Do Change cursor and add subtle visual change

Don't No hover feedback on clickable elements

Code examples
✓ hover:bg-gray-100 cursor-pointer
✗ No hover style

Active States

InteractionAll▶ live demoMedium

Show immediate feedback on press/click

click and hold
click and hold — did it register?

Do Add pressed/active state visual change

Don't No feedback during interaction

Code examples
✓ active:scale-95
✗ No active state

Disabled States

InteractionAll▶ live demoMedium

Clearly indicate non-interactive elements

try clicking Publish
try clicking Publish

Do Reduce opacity and change cursor

Don't Confuse disabled with normal state

Code examples
✓ opacity-50 cursor-not-allowed
✗ Same style as enabled

Loading Buttons

InteractionAll▶ live demoHigh

Prevent double submission during async actions

requests sent: 0
click 5× fast
requests sent: 0
click 5× fast

Do Disable button and show loading state

Don't Allow multiple clicks during processing

Code examples
✓ disabled={loading} spinner
✗ Button clickable while loading

Error Feedback

InteractionAll▶ live demoHigh

Users need to know when something fails

submit while empty
submit while empty — nothing?

Do Show clear error messages near problem

Don't Silent failures with no feedback

Code examples
✓ Red border + error message
✗ No indication of error

Success Feedback

InteractionAll▶ live demoMedium

Confirm successful actions to users

click me
click me — did it work?

Do Show success message or visual change

Don't No confirmation of completed action

Code examples
✓ Toast notification or checkmark
✗ Action completes silently

Confirmation Dialogs

InteractionAll▶ live demoHigh

Prevent accidental destructive actions

Q3-report.pdf
click delete
Q3-report.pdf
click delete

Do Confirm before delete/irreversible actions

Don't Delete without confirmation

Code examples
✓ Are you sure modal
✗ Direct delete on click

Color Contrast

AccessibilityAll▶ live demoHigh

Text must be readable against background

Shipping update
Order #4821 arrives Tuesday.
Shipping update
Order #4821 arrives Tuesday.

Do Minimum 4.5:1 ratio for normal text

Don't Low contrast text

Code examples
✓ #333 on white (7:1)
✗ #999 on white (2.8:1)

Color Only

AccessibilityAll▶ live demoHigh

Don't convey information by color alone

⚠ Invalid email address
hover = color-blind view
hover = color-blind view

Do Use icons/text in addition to color

Don't Red/green only for error/success

Code examples
✓ Red text + error icon
✗ Red border only for error

Alt Text

AccessibilityAll▶ live demoHigh

Images need text alternatives

Golden retriever catching a frisbee in the park
image failed to load
image failed to load

Do Descriptive alt text for meaningful images

Don't Empty or missing alt attributes

Code examples
✓ alt='Dog playing in park'
✗ alt='' for content images

Heading Hierarchy

AccessibilityWebMedium

Screen readers use headings for navigation

Do Use sequential heading levels h1-h6

Don't Skip heading levels or misuse for styling

Code examples
✓ h1 then h2 then h3
✗ h1 then h4

ARIA Labels

AccessibilityAllHigh

Interactive elements need accessible names

Do Add aria-label for icon-only buttons

Don't Icon buttons without labels

Code examples
✓ aria-label='Close menu'
✗ <button><Icon/></button>

Keyboard Navigation

AccessibilityWeb▶ live demoHigh

All functionality accessible via keyboard

tab through
tab through — focus jumps

Do Tab order matches visual order

Don't Keyboard traps or illogical tab order

Code examples
✓ tabIndex for custom order
✗ Unreachable elements

Screen Reader

AccessibilityAllMedium

Content should make sense when read aloud

Do Use semantic HTML and ARIA properly

Don't Div soup with no semantics

Code examples
✓ <nav> <main> <article>
✗ <div> for everything

Form Labels

AccessibilityAll▶ live demoHigh

Inputs must have associated labels

type something
type — which field was this?

Do Use label with for attribute or wrap input

Don't Placeholder-only inputs

Code examples
✓ <label for='email'>
✗ placeholder='Email' only

Error Messages

AccessibilityAllHigh

Error messages must be announced

Do Use aria-live or role=alert for errors

Don't Visual-only error indication

Code examples
✓ role='alert'
✗ Red border only

Image Optimization

PerformanceAllHigh

Large images slow page load

Do Use appropriate size and format (WebP)

Don't Unoptimized full-size images

Code examples
✓ srcset with multiple sizes
✗ 4000px image for 400px display

Lazy Loading

PerformanceAllMedium

Load content as needed

Do Lazy load below-fold images and content

Don't Load everything upfront

Code examples
✓ loading='lazy'
✗ All images eager load

Code Splitting

PerformanceWebMedium

Large bundles slow initial load

Do Split code by route/feature

Don't Single large bundle

Code examples
✓ dynamic import()
✗ All code in main bundle

Caching

PerformanceWebMedium

Repeat visits should be fast

Do Set appropriate cache headers

Don't No caching strategy

Code examples
✓ Cache-Control headers
✗ Every request hits server

Font Loading

PerformanceWeb▶ live demoMedium

Web fonts can block rendering

Welcome back, Sarah. You have three tasks due today, one review waiting on your approval, and a design critique at four this afternoon.

webfont "arrives" on a loop — nothing moves

Welcome back, Sarah. You have three tasks due today, one review waiting on your approval, and a design critique at four this afternoon.

watch the button jump on font load

Do Use font-display swap or optional

Don't Invisible text during font load

Code examples
✓ font-display: swap
✗ FOIT (Flash of Invisible Text)

Third Party Scripts

PerformanceWebMedium

External scripts can block rendering

Do Load non-critical scripts async/defer

Don't Synchronous third-party scripts

Code examples
✓ async or defer attribute
✗ <script src='...'> in head

Bundle Size

PerformanceWebMedium

Large JavaScript slows interaction

Do Monitor and minimize bundle size

Don't Ignore bundle size growth

Code examples
✓ Bundle analyzer
✗ No size monitoring

Render Blocking

PerformanceWebMedium

CSS/JS can block first paint

Do Inline critical CSS defer non-critical

Don't Large blocking CSS files

Code examples
✓ Critical CSS inline
✗ All CSS in head

Input Labels

FormsAll▶ live demoHigh

Every input needs a visible label

type in both panes
type — which field is which?

Do Always show label above or beside input

Don't Placeholder as only label

Code examples
✓ <label>Email</label><input>
✗ placeholder='Email' only

Error Placement

FormsAll▶ live demoMedium

Errors should appear near the problem

press Sign up
press Sign up

Do Show error below related input

Don't Single error message at top of form

Code examples
✓ Error under each field
✗ All errors at form top

Inline Validation

FormsAll▶ live demoMedium

Validate as user types or on blur

type "abc", tab away
type "abc", tab away… silence until Submit

Do Validate on blur for most fields

Don't Validate only on submit

Code examples
✓ onBlur validation
✗ Submit-only validation

Input Types

FormsAll▶ live demoMedium

Use appropriate input types

try typing letters
try typing letters

Do Use email tel number url etc

Don't Text input for everything

Code examples
✓ type='email'
✗ type='text' for email

Autofill Support

FormsWebMedium

Help browsers autofill correctly

Do Use autocomplete attribute properly

Don't Block or ignore autofill

Code examples
✓ autocomplete='email'
✗ autocomplete='off' everywhere

Required Indicators

FormsAll▶ live demoMedium

Mark required fields clearly

* required
which ones are required?

Do Use asterisk or (required) text

Don't No indication of required fields

Code examples
✓ * required indicator
✗ Guess which are required

Password Visibility

FormsAll▶ live demoMedium

Let users see password while typing

check for typos
did you mistype? no way to know

Do Toggle to show/hide password

Don't No visibility toggle

Code examples
✓ Show/hide password button
✗ Password always hidden

Submit Feedback

FormsAll▶ live demoHigh

Confirm form submission status

click it
click it… did it work?

Do Show loading then success/error state

Don't No feedback after submit

Code examples
✓ Loading -> Success message
✗ Button click with no response

Input Affordance

FormsAll▶ live demoMedium

Inputs should look interactive

Ship to
City
obviously editable
Ship to
City
which parts can you edit?

Do Use distinct input styling

Don't Inputs that look like plain text

Code examples
✓ Border/background on inputs
✗ Borderless inputs

Mobile Keyboards

FormsMobileMedium

Show appropriate keyboard for input type

Do Use inputmode attribute

Don't Default keyboard for all inputs

Code examples
✓ inputmode='numeric'
✗ Text keyboard for numbers

Mobile First

ResponsiveWebMedium

Design for mobile then enhance for larger

Do Start with mobile styles then add breakpoints

Don't Desktop-first causing mobile issues

Code examples
✓ Default mobile + md: lg: xl:
✗ Desktop default + max-width queries

Breakpoint Testing

ResponsiveWebMedium

Test at all common screen sizes

Do Test at 320 375 414 768 1024 1440

Don't Only test on your device

Code examples
✓ Multiple device testing
✗ Single device development

Touch Friendly

ResponsiveWeb▶ live demoHigh

Mobile layouts need touch-sized targets

Mobile toolbar
44px targets — tap with a thumb
Mobile toolbar
22px targets, 2px apart

Do Increase touch targets on mobile

Don't Same tiny buttons on mobile

Code examples
✓ Larger buttons on mobile
✗ Desktop-sized targets on mobile

Readable Font Size

ResponsiveAll▶ live demoHigh

Text must be readable on all devices

Your order ships tomorrow. Track it anytime from your account page.

Your order ships tomorrow. Track it anytime from your account page.

Do Minimum 16px body text on mobile

Don't Tiny text on mobile

Code examples
✓ text-base or larger
✗ text-xs for body text

Viewport Meta

ResponsiveWebHigh

Set viewport for mobile devices

Do Use width=device-width initial-scale=1

Don't Missing or incorrect viewport

Code examples
✓ <meta name='viewport'...>
✗ No viewport meta tag

Horizontal Scroll

ResponsiveWeb▶ live demoHigh

Avoid horizontal scrolling

Dashboard

Content wraps to fit whatever width the screen gives it.

Dashboard

This layout is a fixed 480px wide, whatever your screen says.

scroll the page sideways

Do Ensure content fits viewport width

Don't Content wider than viewport

Code examples
✓ max-w-full overflow-x-hidden
✗ Horizontal scrollbar on mobile

Image Scaling

ResponsiveWeb▶ live demoMedium

Images should scale with container

Fluid: fills its container, never spills.

Fixed 420px: the right side is cut off.

Do Use max-width: 100% on images

Don't Fixed width images overflow

Code examples
✓ max-w-full h-auto
✗ width='800' fixed

Table Handling

ResponsiveWeb▶ live demoMedium

Tables can overflow on mobile

InvoiceDateCustomerAmountStatus
#1042Aug 2Acme Corp$1,250Paid
#1043Aug 3Northwind$840Due
scroll the table
InvoiceDateCustomerAmountStatus
#1042Aug 2Acme Corp$1,250Paid
#1043Aug 3Northwind$840Due
columns are lost — no way to reach them

Do Use horizontal scroll or card layout

Don't Wide tables breaking layout

Code examples
✓ overflow-x-auto wrapper
✗ Table overflows viewport

Line Height

TypographyAll▶ live demoMedium

Adequate line height improves readability

Line spacing gives each row of text room to breathe, so your eye finds the start of the next line without effort and reading feels easy.

Line spacing gives each row of text room to breathe, so your eye finds the start of the next line without effort and reading feels easy.

Do Use 1.5-1.75 for body text

Don't Cramped or excessive line height

Code examples
✓ leading-relaxed (1.625)
✗ leading-none (1)

Line Length

TypographyWeb▶ live demoMedium

Long lines are hard to read

A comfortable measure of roughly 65 to 75 characters lets your eye travel a short, predictable distance before it sweeps back, so you land on the next line without losing your place and reading long passages stays effortless.

A comfortable measure of roughly 65 to 75 characters lets your eye travel a short, predictable distance before it sweeps back, so you land on the next line without losing your place and reading long passages stays effortless.

Do Limit to 65-75 characters per line

Don't Full-width text on large screens

Code examples
✓ max-w-prose
✗ Full viewport width text

Font Size Scale

TypographyAll▶ live demoMedium

Consistent type hierarchy aids scanning

Quarterly report

Revenue summary

Sales grew 12% over the previous quarter, led by the new starter plan.

Updated Aug 4 · Finance team

Quarterly report

Revenue summary

Sales grew 12% over the previous quarter, led by the new starter plan.

Updated Aug 4 · Finance team

Do Use consistent modular scale

Don't Random font sizes

Code examples
✓ Type scale (12 14 16 18 24 32)
✗ Arbitrary sizes

Font Loading

TypographyWeb▶ live demoMedium

Fonts should load without layout shift

Welcome back, Sarah. You have three tasks due today, one review waiting on your approval, and a design critique at four this afternoon.

webfont "arrives" on a loop — nothing moves

Welcome back, Sarah. You have three tasks due today, one review waiting on your approval, and a design critique at four this afternoon.

watch the button jump on font load

Do Reserve space with fallback font

Don't Layout shift when fonts load

Code examples
✓ font-display: swap + similar fallback
✗ No fallback font

Contrast Readability

TypographyAll▶ live demoHigh

Body text needs good contrast

Your subscription renews on August 12. Cancel anytime before then at no charge.

Your subscription renews on August 12. Cancel anytime before then at no charge.

Do Use darker text on light backgrounds

Don't Gray text on gray background

Code examples
✓ text-gray-900 on white
✗ text-gray-400 on gray-100

Heading Clarity

TypographyAll▶ live demoMedium

Headings should stand out from body

Shipping policy

Orders placed before 2pm ship the same day. Free returns within 30 days.

Payment

We accept all major cards and invoicing for teams.

Shipping policy

Orders placed before 2pm ship the same day. Free returns within 30 days.

Payment

We accept all major cards and invoicing for teams.

Do Clear size/weight difference

Don't Headings similar to body text

Code examples
✓ Bold + larger size
✗ Same size as body

Loading Indicators

FeedbackAll▶ live demoHigh

Show system status during waits

click — status is shown while you wait
click — did it even register?

Do Show spinner/skeleton for operations > 300ms

Don't No feedback during loading

Code examples
✓ Skeleton or spinner
✗ Frozen UI

Empty States

FeedbackAll▶ live demoMedium

Guide users when no content exists

No projects yet

Projects keep your tasks and files together.

Do Show helpful message and action

Don't Blank empty screens

Code examples
✓ No items yet. Create one!
✗ Empty white space

Error Recovery

FeedbackAll▶ live demoMedium

Help users recover from errors

Upload failed — the connection dropped.

click Try again

Upload failed.

now what?

Do Provide clear next steps

Don't Error without recovery path

Code examples
✓ Try again button + help link
✗ Error message only

Progress Indicators

FeedbackAll▶ live demoMedium

Show progress for multi-step processes

Step 1 of 3 — Account

click Next — you know where you are

Account

click Next — how much is left?

Do Step indicators or progress bar

Don't No indication of progress

Code examples
✓ Step 2 of 4 indicator
✗ No step information

Toast Notifications

FeedbackAll▶ live demoMedium

Transient messages for non-critical info

click — toast leaves after 3s
click a few times — they never leave

Do Auto-dismiss after 3-5 seconds

Don't Toasts that never disappear

Code examples
✓ Auto-dismiss toast
✗ Persistent toast

Confirmation Messages

FeedbackAll▶ live demoMedium

Confirm successful actions

click — you know it worked
click — did it save?

Do Brief success message

Don't Silent success

Code examples
✓ Saved successfully toast
✗ No confirmation

Truncation

ContentAll▶ live demoMedium

Handle long content gracefully

Migration notes: moving the billing service to the new region, rotating keys, and updating every webhook consumer before the cutover window

click Show more

Migration notes: moving the billing service to the new region, rotating keys, and updating every webhook consumer before the cutover window

rest of the title is just gone

Do Truncate with ellipsis and expand option

Don't Overflow or broken layout

Code examples
✓ line-clamp-2 with expand
✗ Overflow or cut off

Date Formatting

ContentAll▶ live demoLow

Use locale-appropriate date formats

Maya commented

Looks good — merging after the tests pass.

Maya commented

Looks good — merging after the tests pass.

Jan 2? Feb 1? 2003?

Do Use relative or locale-aware dates

Don't Ambiguous date formats

Code examples
✓ 2 hours ago or locale format
✗ 01/02/03

Number Formatting

ContentAll▶ live demoLow

Format large numbers for readability

1.2MDownloads
$48,250Revenue
1204387Downloads
$48250.00Revenue

Do Use thousand separators or abbreviations

Don't Long unformatted numbers

Code examples
✓ 1.2K or 1,234
✗ 1234567

Placeholder Content

ContentAll▶ live demoLow

Show realistic placeholders during dev

SC
Sarah ChenProduct designer · Berlin

Designing checkout flows at Klarna. Previously led design systems at a fintech startup.

LI
Lorem IpsumDolor sit amet · Consectetur

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.

does the layout survive real names?

Do Use realistic sample data

Don't Lorem ipsum everywhere

Code examples
✓ Real sample content
✗ Lorem ipsum

User Freedom

OnboardingAll▶ live demoMedium

Users should be able to skip tutorials

Your dashboard

Tip 1 of 3: pin your favorite reports here.

skip whenever you like

Your dashboard

Tip 1 of 3: pin your favorite reports here.

no way out until it ends

Do Provide Skip and Back buttons

Don't Force linear unskippable tour

Code examples
✓ Skip Tutorial button
✗ Locked overlay until finished

Autocomplete

SearchWeb▶ live demoMedium

Help users find results faster

type “ap”
type “ap”… nothing until Enter

Do Show predictions as user types

Don't Require full type and enter

Code examples
✓ Debounced fetch + dropdown
✗ No suggestions

No Results

SearchWeb▶ live demoMedium

Dead ends frustrate users

edit the query
edit the query

Do Show 'No results' with suggestions

Don't Blank screen or '0 results'

Code examples
✓ Try searching for X instead
✗ No results found.

Bulk Actions

Data EntryWeb▶ live demoLow

Editing one by one is tedious

tick a few boxes
archive them… one by one

Do Allow multi-select and bulk edit

Don't Single row actions only

Code examples
✓ Checkbox column + Action bar
✗ Repeated actions per row

Disclaimer

AI InteractionAll▶ live demoHigh

Users need to know they talk to AI

Can I get a refund?
AssistantAI
Sure — orders can be refunded within 30 days.
AI-generated · may contain mistakes
Can I get a refund?
ETEmma Torres · Customer Support
Sure — orders can be refunded within 30 days.
same bot, posing as a person

Do Clearly label AI generated content

Don't Present AI as human

Code examples
✓ AI Assistant label
✗ Fake human name without label

Streaming

AI InteractionAll▶ live demoMedium

Waiting for full text is slow

click — words arrive at once

click — now stare at the spinner

Do Stream text response token by token

Don't Show loading spinner for 10s+

Code examples
✓ Typewriter effect
✗ Spinner until 100% complete

Gaze Hover

Spatial UIVisionOSHigh

Elements should respond to eye tracking before pinch

Do Scale/highlight element on look

Don't Static element until pinch

Code examples
✓ hoverEffect()
✗ onTap only

Depth Layering

Spatial UIVisionOS▶ live demoMedium

UI needs Z-depth to separate content from environment

Now PlayingOcean Drive
glass keeps the room visible
Now PlayingOcean Drive
opaque slab walls off the room

Do Use glass material and z-offset

Don't Flat opaque panels blocking view

Code examples
✓ .glassBackgroundEffect()
✗ bg-white

Auto-Play Video

SustainabilityWeb▶ live demoMedium

Video consumes massive data and energy

plays only when you ask
autoplay · loop
already burning data

Do Click-to-play or pause when off-screen

Don't Auto-play high-res video loops

Code examples
✓ playsInline muted preload='none'
✗ autoplay loop

Asset Weight

SustainabilityWebMedium

Heavy 3D/Image assets increase carbon footprint

Do Compress and lazy load 3D models

Don't Load 50MB textures

Code examples
✓ Draco compression
✗ Raw .obj files

Feedback Loop

AI InteractionAll▶ live demoLow

AI needs user feedback to improve

Paris is the capital of France.

Paris is the capital of France.

wrong or unhelpful? tough luck

Do Thumps up/down or 'Regenerate'

Don't Static output only

Code examples
✓ Feedback component
✗ Read-only text

Motion Sensitivity

AccessibilityAll▶ live demoHigh

Parallax/Scroll-jacking causes nausea

toggle it — motion stops
toggle it — ignored, keeps bouncing

Do Respect prefers-reduced-motion

Don't Force scroll effects

Code examples
✓ @media (prefers-reduced-motion)
✗ ScrollTrigger.create()

Icon Button Labels

AccessibilityWeb▶ live demoCritical

Icon-only buttons must have accessible names

Screen reader:

hover / tab the button

Screen reader:

hover / tab the button

Do Add aria-label to icon buttons

Don't Icon button without label

Code examples
✓ <button aria-label='Close'><XIcon /></button>
✗ <button><XIcon /></button>

Form Control Labels

AccessibilityWeb▶ live demoCritical

All form controls need labels or aria-label

type — the name stays; click “Email” to focus
type — “Email” vanishes

Do Use label element or aria-label

Don't Input without accessible name

Code examples
✓ <label for='email'>Email</label><input id='email' />
✗ <input placeholder='Email' />

Keyboard Handlers

AccessibilityWeb▶ live demoHigh

Interactive elements must support keyboard interaction

Add to cart

Cart: 0

Tab to it, press Enter
Add to cart

Cart: 0

Tab… you can never reach it

Do Add onKeyDown alongside onClick

Don't Click-only interaction

Code examples
✓ <div onClick={fn} onKeyDown={fn} tabIndex={0}>
✗ <div onClick={fn}>

Semantic HTML

AccessibilityWeb▶ live demoHigh

Use semantic HTML before ARIA attributes

 

<button> — Tab + Enter/Space free of charge
Submit

 

<div role="button"> — looks same, keyboard dead

Do Use button/a/label elements

Don't Div with role attribute

Code examples
✓ <button onClick={fn}>Submit</button>
✗ <div role='button' onClick={fn}>Submit</div>

Aria Live

AccessibilityWeb▶ live demoMedium

Async updates need aria-live for screen readers

Screen reader hears:

click save

Screen reader hears:

click save — silence

Do Add aria-live='polite' for dynamic content

Don't Silent async updates

Code examples
✓ <div aria-live='polite'>{status}</div>
✗ <div>{status}</div> // no announcement

Decorative Icons

AccessibilityWeb▶ live demoMedium

Decorative icons should be hidden from screen readers

Screen reader:

hover / tab it

Screen reader:

hover / tab it

Do Add aria-hidden='true' to decorative icons

Don't Decorative icon announced

Code examples
✓ <Icon aria-hidden='true' />
✗ <Icon /> // announced as 'image'

Visible Focus States

FocusWeb▶ live demoCritical

All interactive elements need visible focus states

Tab through — you always know where you are
Tab through — where are you?

Do Use :focus-visible with ring/outline

Don't No focus indication

Code examples
✓ focus-visible:ring-2 focus-visible:ring-blue-500
✗ outline-none // no replacement

Never Remove Outline

FocusWeb▶ live demoCritical

Never remove outline without providing replacement

outline removed — but a ring replaces it (Tab)
outline removed — nothing replaces it (Tab)

Do Replace outline with visible alternative

Don't Remove outline completely

Code examples
✓ focus:outline-none focus:ring-2
✗ focus:outline-none // nothing else

Checkbox Radio Hit Target

FocusWeb▶ live demoMedium

Checkbox/radio must share hit target with label

click anywhere on the row
Email me updates
Weekly digest
click the text — nothing; aim for the 14px box

Do Wrap input and label together

Don't Separate tiny checkbox

Code examples
✓ <label class='flex gap-2'><input type='checkbox' /><span>Option</span></label>
✗ <input type='checkbox' id='x' /><label for='x'>Option</label>

Autocomplete Attribute

FormsWebHigh

Inputs need autocomplete attribute for autofill

Do Add appropriate autocomplete value

Don't Missing autocomplete

Code examples
✓ <input autocomplete='email' type='email' />
✗ <input type='email' />

Semantic Input Types

FormsWeb▶ live demoMedium

Use semantic input type attributes

Not a valid email address Looks good type "abc", then a real email
Accepts anything — no validation, no email keyboard type "abc" — nothing catches it

Do Use email/tel/url/number types

Don't text type for everything

Code examples
✓ <input type='email' />
✗ <input type='text' /> // for email

Never Block Paste

FormsWeb▶ live demoHigh

Never prevent paste functionality

Copy this code: X7-K2-9Q copy the code, paste it here
Copy this code: X7-K2-9Q Paste blocked — type it by hand try pasting — it's blocked

Do Allow paste on all inputs

Don't Block paste on password/code

Code examples
✓ <input type='password' />
✗ <input onPaste={e => e.preventDefault()} />

Spellcheck Disable

FormsWebLow

Disable spellcheck on emails and codes

Do Set spellcheck='false' on codes

Don't Spellcheck on technical input

Code examples
✓ <input spellCheck='false' type='email' />
✗ <input type='email' /> // red squiggles

Submit Button Enabled

FormsWeb▶ live demoMedium

Keep submit enabled and show spinner during requests

click — stays alive, shows progress
click — button goes dead, no feedback

Do Show loading spinner keep enabled

Don't Disable button during submit

Code examples
✓ <button>{loading ? <Spinner /> : 'Submit'}</button>
✗ <button disabled={loading}>Submit</button>

Inline Errors

FormsWeb▶ live demoHigh

Show error messages inline near the problem field

Name is required Email is required submit empty — errors sit on the fields
⚠ The form contains 2 errors.
submit empty — which field was it?

Do Inline error with focus on first error

Don't Single error at top

Code examples
✓ <input /><span class='text-red-500'>{error}</span>
✗ <div class='error'>{allErrors}</div> // at top

Virtualize Lists

PerformanceWebHigh

Virtualize lists exceeding 50 items

Do Use virtual list for large datasets

Don't Render all items

Code examples
✓ <VirtualList items={items} />
✗ items.map(item => <Item />)

Avoid Layout Reads

PerformanceWebMedium

Avoid layout reads during render phase

Do Read layout in effects or callbacks

Don't getBoundingClientRect in render

Code examples
✓ useEffect(() => { el.getBoundingClientRect() })
✗ const rect = el.getBoundingClientRect() // in render

Batch DOM Operations

PerformanceWebMedium

Group DOM operations to minimize reflows

Do Batch writes then reads

Don't Interleave reads and writes

Code examples
✓ writes.forEach(w => w()); reads.forEach(r => r())
✗ write(); read(); write(); read(); // thrashing

Preconnect CDN

PerformanceWeb

Add preconnect links for CDN domains

Do Preconnect to known domains

Don't <link rel='preconnect' href='https://cdn.example.com' />

Code examples
✓ // no preconnect hint
✗ Low

Lazy Load Images

PerformanceWebMedium

Lazy-load images below the fold

Do Use loading='lazy' for below-fold images

Don't Load all images eagerly

Code examples
✓ <img loading='lazy' src='...' />
✗ <img src='...' /> // above fold only

URL Reflects State

StateWeb▶ live demoHigh

URL should reflect current UI state

/reports
Overview charts
switch tab, then hit ⟳
/reports
Overview charts
switch tab, hit ⟳ — state lost

Do Sync filters/tabs/pagination to URL

Don't State only in memory

Code examples
✓ ?tab=settings&page=2
✗ useState only // lost on refresh

Deep Linking

StateWebMedium

Stateful components should support deep-linking

Do Enable sharing current view via URL

Don't No shareable state

Code examples
✓ router.push({ query: { ...filters } })
✗ setFilters(f) // not in URL

Confirm Destructive Actions

StateWeb▶ live demoHigh

Destructive actions require confirmation

Q3-report.pdf
Delete "Q3-report.pdf"?
Deleted.
click Delete — it asks first
Q3-report.pdf
Gone. Hope you meant that.
click Delete — instantly gone

Do Show confirmation dialog before delete

Don't Delete without confirmation

Code examples
✓ if (confirm('Delete?')) delete()
✗ onClick={delete} // no confirmation

Proper Unicode

TypographyWeb▶ live demoLow

Use proper Unicode characters

Loading… ellipsis

“Nice work” curly quotes

2019–2024 en dash

It’s ready apostrophe

Loading... three dots

"Nice work" straight quotes

2019-2024 hyphen

It's ready typewriter tick

Do Use ... curly quotes proper dashes

Don't ASCII approximations

Code examples
✓ 'Hello...' with proper ellipsis
✗ 'Hello...' with three dots

Text Overflow

TypographyWeb▶ live demoMedium

Handle text overflow properly

quarterly_financials_FINAL_v7_revised.xlsx 2.4 MB · edited today
hover the name for the full title
quarterly_financials_FINAL_v7_revised.xlsx 2.4 MB · edited today
name bleeds out of its card

Do Use truncate/line-clamp/break-words

Don't Text overflows container

Code examples
✓ <p class='truncate'>Long text...</p>
✗ <p>Long text...</p> // overflows

Non-Breaking Spaces

TypographyWeb▶ live demo

Use non-breaking spaces for units and brand names

Maximum weight 10 kg

drag the corner — "10 kg" stays together

Maximum weight 10 kg

drag the corner — "kg" strands alone

Do Use &nbsp; between number and unit

Don't 10&nbsp;kg or Next.js&nbsp;14

Code examples
✓ 10 kg // may wrap
✗ Low

No Zoom Disable

Anti-PatternWeb

Never disable zoom in viewport meta

Do Allow user zoom

Don't <meta name='viewport' content='width=device-width'>

Code examples
✓ <meta name='viewport' content='maximum-scale=1'>
✗ Critical

No Transition All

Anti-PatternWeb▶ live demoMedium

Avoid transition: all - specify properties

hover · tab — color fades, focus ring is instant
hover · tab — focus ring oozes in late

Do Transition specific properties

Don't transition: all

Code examples
✓ transition-colors duration-200
✗ transition-all duration-200

Outline Replacement

Anti-PatternWeb▶ live demoCritical

Never use outline-none without replacement

tab into this — ring replaces outline
tab into this — focus is invisible

Do Provide visible focus replacement

Don't Remove outline with nothing

Code examples
✓ focus:outline-none focus:ring-2 focus:ring-blue-500
✗ focus:outline-none // alone

No Hardcoded Dates

Anti-PatternWeb▶ live demoMedium

Use Intl for date/number formatting

switch locale — format follows
switch locale — nothing adapts

Do Use Intl.DateTimeFormat

Don't Hardcoded date format

Code examples
✓ new Intl.DateTimeFormat('en').format(date)
✗ date.toLocaleDateString() // or manual format