The 18 principles
Every action feels instant
UI explains itself
Short slugs, no UUIDs
Resume where you left off
Plus shades of gray
Hidden until scrolling
Anywhere in 3 clicks
SVG logo, colors, fonts
Layout shape, not spinners
Copy codes, keys, URLs
44px minimum touch area
One click, no guilt trips
Command palette for power users
Only on icon-only buttons
7 words max per sentence
Visual weight, not pixels
F-pattern scan optimized
Auto-save, undo, version history
100ms interactions
Every interaction completes in under 100ms. If it can't, fake it with optimistic updates — show the result before the server confirms.
// Optimistic delete — remove immediately, reconcile later
async function handleDelete(id) {
setItems(prev => prev.filter(i => i.id !== id));
try {
await api.delete(`/items/${id}`);
} catch {
setItems(prev => [...prev, originalItem]);
toast("Couldn't delete. Restored.");
}
}
- Prefetch likely next routes on hover
- Use
transformfor animations, nevertop/left - Measure with
performance.now(), not gut feel
Skeleton loading states
Never show a spinner when you know the shape of what's coming. Render a skeleton that matches the layout, then swap in real content.
.skeleton {
background: linear-gradient(
90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 4px;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
No product tours
If you need a tour to explain your UI, the UI is wrong. Instead:
"Create your first project"
Show features when relevant
Disappear after first use
Work without configuration
Clean URLs
Slugs are short, readable, and human-guessable. No UUIDs, no query param soup.
/projects/weather-app
/settings/billing
/docs/api/auth
/projects/550e8400-e29b-41d4...
/app?view=settings&tab=billing
/dashboard#!/module/list
Persistent resumable state
Users leave and come back. Respect that.
- Save draft form state to localStorage or the server
- Restore scroll position on back navigation
- Preserve filter/sort selections across sessions
- URL encodes the view state — sharing reproduces the view
3 colors max
One primary, one accent, one for danger. Everything else is shades of gray.
If you reach for a 4th color, you're compensating for weak layout.
No visible scrollbars
Hide them unless the user is actively scrolling. Use scroll shadows to hint at overflow without chrome.
.scroll-container {
overflow-y: auto;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
.scroll-container::-webkit-scrollbar {
display: none; /* Chrome/Safari */
}
Command palette
Every app with more than one page needs Cmd + K.
useEffect(() => {
function handleKeyDown(e) {
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
e.preventDefault();
setCommandPaletteOpen(true);
}
}
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, []);
- Fuzzy search over pages, recent actions, settings
- Show keyboard shortcuts inline
- Most recent items first
- No categories until 20+ commands
Clipboard support
One-click copy on codes, URLs, API keys, IDs. Paste into file uploads and image fields. Brief confirmation that auto-dismisses.
async function copyToClipboard(text, label = "Copied") {
await navigator.clipboard.writeText(text);
toast(label, { duration: 1500 });
}
Large hit targets
Minimum 44x44px touch targets (WCAG 2.5.8). On desktop, generous padding is still faster than precise aim.
button, .btn, [role="button"] {
min-height: 44px;
min-width: 44px;
padding: 10px 20px;
}
input, select, textarea {
min-height: 44px;
padding: 10px 12px;
font-size: 16px; /* Prevents iOS zoom on focus */
}
- Adjacent clickable elements: 8px gap minimum
- Icon-only buttons get larger padding
- Don't rely on hover states — they don't exist on touch
Honest cancellation
One-click cancel. No guilt trips, no dark patterns.
- Cancel button always visible
- Account deletion works first try
- Unsubscribe is one click
- "Are you sure you want to miss out?"
- Preference center instead of unsubscribe
- "Contact support to cancel"
Minimal tooltips
Tooltips are a confession that the UI doesn't speak for itself.
- Only on icon-only buttons (to provide the label)
- Never on text that's already readable
- Show on hover after 300ms delay
- Dismiss on scroll
- Never for essential information
Active voice copy
Max 7 words per sentence. Talk like a person, not a legal document.
- "Project created"
- "Saved 2 minutes ago"
- "Delete this file?"
- "Successfully created!"
- "Changes were last saved..."
- "This action cannot be undone."
Buttons are verbs: "Save", "Delete", "Send" — not "Submit", "OK", "Confirm". Sentence case everywhere, never Title Case.
Optical alignment
The eye doesn't see pixels, it sees weight. Optical alignment over geometric.
/* Play icon: shift right to look centered */
.play-button svg {
transform: translateX(2px);
}
/* Visually balanced card padding */
.card {
padding: 20px 24px 22px 24px;
}
- Icons next to text need 1-2px vertical offset
- Bottom padding is often 1-2px more than top
- Leading capitals align optically left of bounding box
L-to-R reading flow
Optimized for the F-pattern scan.
- Most important content in top-left quadrant
- Primary actions on the right (where the eye ends a line)
- Labels above inputs, not beside them
- Most-scanned table column is leftmost
- Left-align everything except single-line headings
Reassurance about loss
Users fear losing work. Prevent it and prove it.
// Warn on unsaved changes
useEffect(() => {
function handleBeforeUnload(e) {
if (hasUnsavedChanges) {
e.preventDefault();
e.returnValue = "";
}
}
window.addEventListener("beforeunload", handleBeforeUnload);
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
}, [hasUnsavedChanges]);
- Auto-save with visible "Saved" indicator
- Undo after destructive actions (soft delete)
- Version history for anything longer than a tweet
- Confirmation only for irreversible actions
Copyable brand assets
Ship a /brand or /press page with downloadable assets. Don't make people screenshot your logo.
- SVG logo with transparent background
- Color codes (hex, RGB, HSL)
- Font names and weights
- Usage guidelines and clear space rules
- One-click download as ZIP
Review checklist
Run this against any web UI:
Installation
Install the skill
# Clone the repository
git clone https://github.com/jamditis/claude-skills-journalism.git
# Copy the skill to your Claude config
cp -r claude-skills-journalism/web-ui-best-practices ~/.claude/skills/
Or download just this skill from the GitHub repository.
Related skills
Taste is in the details
18 principles. Zero tolerance for dark patterns. Every interaction under 100ms.
View on GitHub