Review and guide UI implementations using the 21 Laws of UX. Identifies usability issues in HTML, CSS, and JavaScript by applying established cognitive, visual, and behavioral principles. Use when reviewing UI code, building new interfaces, or auditing user experience.
64
58%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./skills/laws-of-ux/SKILL.mdThis skill guides AI in reviewing and building user interfaces using the 21 Laws of UX. It serves two purposes:
The laws are organized into three categories based on what aspect of the user experience they address:
When reviewing code, check the Review Checklist first to identify which laws are most relevant, then refer to the detailed sections for guidance and examples.
Keywords: UX review, UI review, usability, Laws of UX, UX best practices, user experience, UX audit, UI patterns
Use this table for quick scanning. Each check maps to one or more laws and tells you what to look for in code.
| Check | Law(s) | What to Look For |
|---|---|---|
| Navigation has 7 or fewer top-level items | Miller's Law | nav, menu, sidebar — count direct children |
| Choices are minimized per step | Hick's Law | <select> option counts, radio groups, button arrays |
| Click targets are at least 44x44px | Fitts's Law | Button/link min-height, min-width, padding |
| Important actions are large and easy to reach | Fitts's Law | CTA sizing and placement in layout |
| Loading feedback appears within 400ms | Doherty Threshold | Spinners, skeleton screens, disabled states |
| Forms accept flexible input formats | Postel's Law | Input validation, masking, format requirements |
| One primary CTA is visually distinct | Von Restorff Effect | Button variant classes, color emphasis |
| Related items are visually grouped | Proximity, Common Region | Spacing, borders, background grouping |
| Progress indicators on multi-step flows | Zeigarnik Effect, Goal-Gradient | Step indicators, progress bars |
| Key actions at start/end of lists | Serial Position Effect | Nav ordering, list structure |
| Interface follows platform conventions | Jakob's Law | Standard patterns vs custom widgets |
| UI is visually polished and consistent | Aesthetic-Usability Effect | Design token usage, consistent styling |
| Complexity is handled by the system, not the user | Tesler's Law | Smart defaults, auto-detection, pre-filled values |
| Most-used features are prioritized | Pareto Principle | Layout hierarchy, feature prominence |
| Forms and flows are appropriately scoped | Parkinson's Law | Step count, field count, time constraints |
| Final interactions leave a positive impression | Peak-End Rule | Success states, confirmation pages, error recovery |
| Visual hierarchy is clean and simple | Law of Prägnanz | Layout clarity, minimal visual noise |
| Consistent visual styling signals relatedness | Law of Similarity | Consistent classes for related elements |
| Connected elements share visual indicators | Uniform Connectedness | Lines, borders, shared backgrounds |
| Simplest explanation wins | Occam's Razor | UI complexity vs task requirements |
| Multi-step tasks show progress and momentum | Goal-Gradient Effect | Progress bars, step completion feedback |
These laws address how users process information, make decisions, and manage mental effort.
Definition: The average person can hold approximately 7 (plus or minus 2) items in working memory at one time.
Key Takeaway: Chunk content into groups of 5-9 items. When more items are needed, use hierarchy and grouping to reduce cognitive load.
What to look for in code:
Examples:
✅ GOOD
<nav class="main-nav">
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/team">Team</a>
<a href="/reports">Reports</a>
<a href="/settings">Settings</a>
</nav>🚫 BAD
<nav class="main-nav">
<a href="/dashboard">Dashboard</a>
<a href="/projects">Projects</a>
<a href="/team">Team</a>
<a href="/reports">Reports</a>
<a href="/analytics">Analytics</a>
<a href="/settings">Settings</a>
<a href="/billing">Billing</a>
<a href="/integrations">Integrations</a>
<a href="/support">Support</a>
<a href="/docs">Documentation</a>
<a href="/profile">Profile</a>
<a href="/admin">Admin</a>
</nav>12 flat navigation items overwhelm working memory. Group under dropdowns or consolidate.
Review flags:
<select> elements with more than 10 ungrouped options (suggest <optgroup>)Definition: The time it takes to make a decision increases with the number and complexity of choices available.
Key Takeaway: Reduce the number of choices presented at any given time. Break complex decisions into smaller, sequential steps.
What to look for in code:
Examples:
✅ GOOD
<div class="pricing-options">
<div class="pricing-card">
<h3>Basic</h3>
<button class="btn btn--outline">Select</button>
</div>
<div class="pricing-card pricing-card--recommended">
<span class="badge">Recommended</span>
<h3>Pro</h3>
<button class="btn btn--primary">Select</button>
</div>
<div class="pricing-card">
<h3>Enterprise</h3>
<button class="btn btn--outline">Contact Us</button>
</div>
</div>🚫 BAD
<div class="pricing-options">
<div class="pricing-card"><h3>Free</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Starter</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Basic</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Pro</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Business</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Enterprise</h3><button class="btn">Select</button></div>
<div class="pricing-card"><h3>Custom</h3><button class="btn">Select</button></div>
</div>Seven visually identical options with no recommended choice. Reduce options and highlight the best default.
Review flags:
Definition: Every application has an inherent amount of complexity that cannot be removed or hidden. It must be dealt with by either the system or the user.
Key Takeaway: Absorb complexity into the system so users don't have to deal with it. Use smart defaults, auto-detection, and pre-filled values.
What to look for in code:
Examples:
✅ GOOD
<form>
<label for="phone">Phone Number</label>
<input type="tel" id="phone" placeholder="(555) 123-4567"
data-controller="phone-format"
data-action="input->phone-format#format">
<!-- System handles formatting — user types digits freely -->
</form>🚫 BAD
<form>
<label for="phone">Phone Number (format: +1-XXX-XXX-XXXX)</label>
<input type="text" id="phone" pattern="\+1-\d{3}-\d{3}-\d{4}">
<span class="help-text">Must include country code and dashes</span>
</form>The burden of formatting is placed on the user instead of the system.
Review flags:
Definition: Among competing hypotheses that explain the same observations, the one with the fewest assumptions should be selected.
Key Takeaway: Prefer the simplest UI that accomplishes the task. Remove unnecessary elements, steps, and visual complexity.
What to look for in code:
Examples:
✅ GOOD
<div class="empty-state">
<p>No projects yet.</p>
<a href="/projects/new" class="btn btn--primary">Create your first project</a>
</div>🚫 BAD
<div class="empty-state">
<img src="/images/empty-illustration.svg" alt="">
<h2>Welcome to Your Dashboard!</h2>
<p>It looks like you haven't created any projects yet. Projects help you organize your work and collaborate with your team members efficiently.</p>
<p>Getting started is easy — just click the button below to create your first project and begin your journey!</p>
<a href="/projects/new" class="btn btn--primary btn--large">Create Project</a>
<a href="/help/getting-started" class="btn btn--outline">Learn More</a>
<p class="text-muted">You can also import projects from other tools.</p>
</div>Excessive content for a simple empty state. The user's goal is clear — help them act on it quickly.
Review flags:
Definition: Any task will inflate until all of the available time is spent.
Key Takeaway: Constrain task scope by setting reasonable boundaries. Reduce form fields to only what is necessary and break large tasks into focused steps.
What to look for in code:
Review flags:
Definition: Roughly 80% of effects come from 20% of causes.
Key Takeaway: Identify the 20% of features and actions that users rely on most, and make those prominent and effortless to access.
What to look for in code:
Review flags:
These laws address how users perceive and interpret visual information on screen.
Definition: Objects that are near each other tend to be perceived as a group.
Key Takeaway: Use spacing to communicate relationships. Related items should be closer together; unrelated items should have more space between them.
What to look for in code:
gap, margin, and padding values — related items should have tighter spacing than between groups<fieldset> or wrapper divs with spacing--op-space-small within groups, --op-space-large between groups)Examples:
✅ GOOD
.form__group {
display: flex;
flex-direction: column;
gap: var(--op-space-x-small); /* Tight spacing within group */
}
.form__section + .form__section {
margin-top: var(--op-space-x-large); /* Larger spacing between sections */
}🚫 BAD
.form label,
.form input,
.form select,
.form textarea {
margin-bottom: 16px; /* Uniform spacing everywhere — no grouping */
}Uniform spacing fails to communicate which fields are related.
Review flags:
<fieldset>, section dividers, or spacing variation)optics-context skill)Definition: Elements that share visual characteristics (color, shape, size) are perceived as related and part of a group.
Key Takeaway: Apply consistent styling to elements that serve the same function. Vary styling deliberately to signal different purposes.
What to look for in code:
Examples:
✅ GOOD
<div class="action-bar">
<button class="btn btn--primary">Save</button>
<button class="btn btn--outline">Cancel</button>
<button class="btn btn--danger">Delete</button>
</div>Three distinct button styles signal three distinct intents.
🚫 BAD
<div class="action-bar">
<button class="btn btn--primary">Save</button>
<button class="btn btn--primary">Cancel</button>
<button class="btn btn--primary">Delete</button>
</div>All buttons look identical despite serving very different purposes.
Review flags:
Definition: Elements within a shared boundary (border, background, or container) are perceived as a group.
Key Takeaway: Use visual containers — backgrounds, borders, cards — to group related content. This reinforces grouping beyond just proximity.
What to look for in code:
<fieldset>, cards, panels, or sections with visible boundariesbackground-color, border, or border-radius used to create container regionsExamples:
✅ GOOD
<fieldset class="form__section">
<legend>Shipping Address</legend>
<input type="text" placeholder="Street">
<input type="text" placeholder="City">
<input type="text" placeholder="Zip">
</fieldset>
<fieldset class="form__section">
<legend>Billing Address</legend>
<input type="text" placeholder="Street">
<input type="text" placeholder="City">
<input type="text" placeholder="Zip">
</fieldset>🚫 BAD
<label>Shipping Street</label>
<input type="text">
<label>Shipping City</label>
<input type="text">
<label>Shipping Zip</label>
<input type="text">
<label>Billing Street</label>
<input type="text">
<label>Billing City</label>
<input type="text">
<label>Billing Zip</label>
<input type="text">Flat list of fields with no grouping. Users cannot quickly identify where shipping ends and billing begins.
Review flags:
<fieldset> usage without <legend> (boundary exists but label is missing)Definition: Elements that are visually connected (by lines, colors, frames, or other shapes) are perceived as more related than elements with no connection.
Key Takeaway: Use visual connectors — lines, shared colors, enclosures — to indicate relationships between elements.
What to look for in code:
Examples:
✅ GOOD
.stepper__step {
display: flex;
align-items: center;
}
.stepper__connector {
flex: 1;
height: 2px;
background-color: var(--op-color-border);
}
.stepper__step--completed .stepper__connector {
background-color: var(--op-color-primary-base);
}Review flags:
Definition: People tend to interpret ambiguous or complex images in the simplest form possible.
Key Takeaway: Keep layouts clean and simple. Use clear visual hierarchy, ample whitespace, and avoid unnecessary visual complexity.
What to look for in code:
Examples:
✅ GOOD
.card {
background: var(--op-color-surface-base);
border-radius: var(--op-radius-medium);
padding: var(--op-space-large);
}🚫 BAD
.card {
background: linear-gradient(135deg, #f5f5f5, #e0e0e0);
border: 2px solid #ccc;
border-radius: 12px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
padding: 24px;
outline: 1px solid rgba(255, 255, 255, 0.5);
}Excessive styling competes for attention and adds visual noise.
Review flags:
optics-context skill)Definition: When multiple similar objects are present, the one that differs most from the rest is most likely to be remembered.
Key Takeaway: Make the most important element visually distinct. Use a single primary CTA style to draw attention to the key action.
What to look for in code:
Examples:
✅ GOOD
<div class="dialog__actions">
<button class="btn btn--outline">Cancel</button>
<button class="btn btn--primary">Confirm Purchase</button>
</div>🚫 BAD
<div class="dialog__actions">
<button class="btn btn--primary">Cancel</button>
<button class="btn btn--primary">Confirm Purchase</button>
</div>Both actions have equal visual weight — the user cannot quickly identify the primary action.
Review flags:
btn--primary (or equivalent) elements competing for attentionDefinition: Users tend to best remember the first and last items in a series.
Key Takeaway: Place the most important items at the beginning and end of lists, navigation, and content sequences.
What to look for in code:
Examples:
✅ GOOD
<nav class="main-nav">
<a href="/dashboard">Dashboard</a> <!-- First: most-used page -->
<a href="/projects">Projects</a>
<a href="/team">Team</a>
<a href="/reports">Reports</a>
<a href="/settings">Settings</a> <!-- Last: memorable position -->
</nav>Review flags:
These laws address how users interact with interfaces and what drives their behavior.
Definition: The time to acquire a target is a function of the distance to and size of the target.
Key Takeaway: Make important interactive elements large and easy to reach. Increase click/tap target sizes, especially on touch devices.
What to look for in code:
Examples:
✅ GOOD
.btn {
min-height: 44px;
min-width: 44px;
padding: var(--op-space-small) var(--op-space-medium);
}
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
min-width: 44px;
}🚫 BAD
.action-link {
font-size: 12px;
padding: 2px 4px;
}
.icon-btn {
width: 20px;
height: 20px;
}Tiny click targets are difficult to tap on touch devices and hard to click precisely on desktop.
Review flags:
Definition: Productivity soars when a computer and its users interact at a pace (<400ms) that ensures neither has to wait on the other.
Key Takeaway: Provide immediate visual feedback for all user actions. Use loading states, optimistic updates, and skeleton screens to keep perceived response time under 400ms.
What to look for in code:
disabled states on buttons during form submissionExamples:
✅ GOOD
<button type="submit" class="btn btn--primary"
data-disable-with="Saving..."
data-controller="submit-button">
Save Changes
</button><!-- Skeleton screen while loading -->
<div class="card card--skeleton">
<div class="skeleton-line skeleton-line--title"></div>
<div class="skeleton-line"></div>
<div class="skeleton-line"></div>
</div>🚫 BAD
<button type="submit" class="btn btn--primary">Save Changes</button>
<!-- No loading state, no disabled state, no visual feedback -->Review flags:
data-disable-with or equivalent loading stateDefinition: The tendency to approach a goal increases with proximity to the goal.
Key Takeaway: Show progress in multi-step tasks. As users get closer to completion, make progress visually apparent to motivate them to finish.
What to look for in code:
Examples:
✅ GOOD
<div class="stepper">
<div class="stepper__step stepper__step--completed">
<span class="stepper__icon">✓</span>
<span>Account</span>
</div>
<div class="stepper__connector stepper__connector--completed"></div>
<div class="stepper__step stepper__step--active">
<span class="stepper__icon">2</span>
<span>Profile</span>
</div>
<div class="stepper__connector"></div>
<div class="stepper__step">
<span class="stepper__icon">3</span>
<span>Preferences</span>
</div>
</div>🚫 BAD
<h2>Profile Information</h2>
<form>
<!-- Multi-step form with no indication of progress or remaining steps -->
<input type="text" placeholder="Name">
<button type="submit">Next</button>
</form>Review flags:
Definition: Users spend most of their time on other sites. They prefer your site to work the same way as all the other sites they already know.
Key Takeaway: Follow established UI conventions. Use standard patterns for navigation, forms, and common interactions. Innovate cautiously.
What to look for in code:
Examples:
✅ GOOD
<header class="header">
<a href="/" class="header__logo">
<img src="/logo.svg" alt="AppName">
</a>
<nav class="header__nav"><!-- standard nav items --></nav>
<div class="header__actions">
<a href="/account" class="header__avatar"><!-- user menu --></a>
</div>
</header>🚫 BAD
<footer>
<a href="/">
<img src="/logo.svg" alt="AppName">
</a>
<nav><!-- main navigation in the footer --></nav>
</footer>Placing primary navigation in the footer breaks user expectations.
Review flags:
Definition: Users often perceive aesthetically pleasing design as design that is more usable.
Key Takeaway: Invest in visual polish. A well-designed interface builds user trust, increases tolerance for minor usability issues, and encourages engagement.
What to look for in code:
Examples:
✅ GOOD
.btn {
background-color: var(--op-color-primary-base);
color: var(--op-color-primary-base-on);
border-radius: var(--op-radius-medium);
padding: var(--op-space-small) var(--op-space-medium);
transition: background-color 150ms ease;
}
.btn:hover {
background-color: var(--op-color-primary-plus-one);
}
.btn:focus-visible {
outline: 2px solid var(--op-color-primary-base);
outline-offset: 2px;
}🚫 BAD
.btn {
background: blue;
color: white;
padding: 8px 12px;
}
/* No hover state, no focus state, no transitions */Missing interaction states and hard-coded colors feel unpolished and reduce perceived quality.
Review flags:
optics-context skill)Definition: People judge an experience largely based on how they felt at its most intense point (peak) and at its end, rather than the sum of every moment.
Key Takeaway: Design positive peak moments and strong endings. Success states, confirmation messages, and completion celebrations matter disproportionately.
What to look for in code:
Examples:
✅ GOOD
<div class="success-state">
<div class="success-state__icon">✓</div>
<h2>Payment Successful!</h2>
<p>Your order #1234 has been confirmed. You'll receive a confirmation email shortly.</p>
<a href="/orders/1234" class="btn btn--primary">View Order</a>
</div>🚫 BAD
<div class="alert alert--success">
<p>Done.</p>
</div>
<!-- Redirects to homepage after 3 seconds -->An abrupt, minimal success message after a complex flow (like checkout) leaves a weak final impression.
Review flags:
Definition: Be liberal in what you accept, and conservative in what you send.
Key Takeaway: Accept a wide range of user input formats and be forgiving of minor mistakes. Auto-format, auto-correct, and provide helpful suggestions rather than strict validation errors.
What to look for in code:
Examples:
✅ GOOD
<input type="tel" placeholder="Phone number"
data-controller="phone-input"
data-action="input->phone-input#format">
<!-- Accepts: 5551234567, 555-123-4567, (555) 123-4567, +1 555 123 4567 -->🚫 BAD
<input type="text" placeholder="XXX-XXX-XXXX" pattern="\d{3}-\d{3}-\d{4}">
<span class="error">Phone number must be in format XXX-XXX-XXXX</span>Rejecting valid phone numbers because of formatting differences.
Review flags:
Definition: People remember uncompleted or interrupted tasks better than completed tasks.
Key Takeaway: Use visual indicators for incomplete tasks to motivate completion. Show what's started but not finished — profile completion bars, incomplete form drafts, saved progress.
What to look for in code:
Examples:
✅ GOOD
<div class="profile-completion">
<div class="progress-bar">
<div class="progress-bar__fill" style="width: 60%"></div>
</div>
<p>Your profile is 60% complete. <a href="/profile/edit">Complete your profile</a></p>
</div>🚫 BAD
<!-- No indication that the user's profile is incomplete -->
<div class="profile-header">
<h2>Welcome, Alex</h2>
</div>Missing the opportunity to motivate profile completion.
Review flags:
Several laws reinforce each other. When reviewing code, group related findings rather than flagging the same issue under multiple law names.
These four laws all relate to how users perceive which elements belong together. When reviewing layouts:
If a layout violates all four, report it as a single grouping issue and reference the most relevant law for the fix.
These laws all address how to manage complexity in the interface:
When a form has too many fields with too many options per field, cite the most impactful law for each specific issue.
These laws all relate to feedback and perceived progress:
In multi-step flows, check all four, but report findings grouped by the specific interaction point rather than by law name.
bem-structure: Use for CSS class naming conventions when creating components that implement these UX laws.optics-context: Use for design token usage (colors, spacing, typography) when implementing visual aspects of these laws.097ad6b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.