Development skill

Web UI best practices

Signs of taste in web UI. The small details that separate polished products from rough ones — speed, restraint, honesty, and respect for the user's time.

The 18 principles

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.");
  }
}

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:

Empty states that teach

"Create your first project"

Progressive disclosure

Show features when relevant

Inline hints

Disappear after first use

Smart defaults

Work without configuration

Clean URLs

Slugs are short, readable, and human-guessable. No UUIDs, no query param soup.

Good
/projects/weather-app
/settings/billing
/docs/api/auth
Bad
/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.

Primary
Accent
Danger
Gray 100
Gray 400
Gray 900

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.

Do
  • Cancel button always visible
  • Account deletion works first try
  • Unsubscribe is one click
Don't
  • "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.

Good
  • "Project created"
  • "Saved 2 minutes ago"
  • "Delete this file?"
Bad
  • "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