Build clear, usable interfaces by understanding visual hierarchy, layout, typography, color, interaction design, feedback, consistency, responsive behavior, and user-centered design principles.
Explain the difference between user interface and user experience design
Create strong visual hierarchy using spacing, typography, color, and scale
Apply layout, alignment, grouping, and consistency principles
Design interactions with clear affordances and feedback
Create responsive interfaces that adapt to different contexts
Evaluate interfaces using usability principles and user-centered thinking
User interface design focuses on the visible and interactive parts of a product, including layout, typography, controls, icons, spacing, and visual states.
User experience design considers the broader experience of completing a goal, including clarity, efficiency, navigation, feedback, error recovery, and whether the product solves the user's actual problem.
UI describes the interface users interact with
UX describes the overall experience of accomplishing a goal
A visually attractive interface can still provide poor usability
UI question:
How should the checkout button look?
UX question:
Can the user understand the checkout flow,
complete payment confidently,
and recover from an error?
Good product design considers both.Visual hierarchy guides attention by making some elements appear more important than others. Designers create hierarchy using size, weight, contrast, position, spacing, and grouping.
A strong hierarchy helps users quickly understand what a page is about, which information matters most, and what action they should take next.
Use size and contrast to communicate importance
Avoid making every element equally prominent
Make primary actions visually distinct from secondary actions
export function PricingCard() {
return (
<article className="pricing-card">
<span className="eyebrow">Pro plan</span>
<h2>$19/month</h2>
<p>
Advanced tools for developers who need
more practice and detailed feedback.
</p>
<button type="button">
Start free trial
</button>
<a href="/pricing/details">
View plan details
</a>
</article>
);
}Spacing communicates relationships. Elements positioned close together are usually perceived as related, while larger gaps communicate separation between groups.
Consistent spacing systems create rhythm and reduce arbitrary visual decisions across an interface.
Use proximity to communicate relationships
Apply consistent spacing values
Use larger spacing between groups than within groups
:root {
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
}
.formGroup {
display: grid;
gap: var(--space-2);
}
.form {
display: grid;
gap: var(--space-6);
}Alignment creates visual order by connecting elements along shared edges, centers, or baselines. Consistent alignment makes interfaces easier to scan.
Layouts should reflect relationships between content instead of placing elements arbitrarily. Grid and flexible layout systems provide predictable structure.
Align related elements consistently
Use a layout system instead of arbitrary positioning
Preserve meaningful whitespace
.settingsPage {
display: grid;
grid-template-columns: 14rem minmax(0, 1fr);
gap: 2rem;
align-items: start;
}
.settingsSection {
display: grid;
gap: 1.5rem;
}
.settingsRow {
display: grid;
grid-template-columns: minmax(10rem, 1fr) 2fr;
gap: 1rem;
align-items: center;
}Typography communicates hierarchy, tone, and structure. Good typography makes content easier to scan and read without relying on excessive font sizes or weights.
A restrained type scale with consistent line heights and readable line lengths usually produces a stronger interface than many unrelated font styles.
Use a small, consistent type scale
Maintain readable line height and line length
Use font weight intentionally rather than making everything bold
:root {
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.5rem;
--text-2xl: 2rem;
}
.pageTitle {
font-size: var(--text-2xl);
line-height: 1.15;
letter-spacing: -0.03em;
}
.bodyText {
max-width: 65ch;
font-size: var(--text-base);
line-height: 1.6;
}Color can communicate hierarchy, state, branding, and emphasis, but it should not be the only way information is communicated.
Strong interfaces usually use a restrained palette where neutral colors handle most surfaces and text while accent colors are reserved for meaningful emphasis.
Use color intentionally rather than decoratively everywhere
Maintain sufficient contrast between foreground and background
Do not communicate status through color alone
:root {
--surface-primary: #ffffff;
--surface-muted: #f8fafc;
--text-primary: #0f172a;
--text-secondary: #475569;
--border-subtle: #e2e8f0;
--action-primary: #2563eb;
--status-danger: #b91c1c;
}
.errorMessage {
color: var(--status-danger);
font-weight: 500;
}An affordance communicates how something can be used. Buttons should look interactive, inputs should look editable, and links should be recognizable as navigation.
Users should not need to experiment randomly to discover basic interactions.
Make interactive elements visibly interactive
Use familiar interaction patterns when they already solve the problem
Avoid hiding important actions behind unclear visual treatment
export function CourseActions() {
return (
<div className="course-actions">
<button className="button button--primary">
Continue lesson
</button>
<button className="button button--secondary">
Save for later
</button>
<a href="/courses">
Back to courses
</a>
</div>
);
}Interfaces should communicate what is happening after a user performs an action. Feedback can indicate loading, success, failure, progress, or disabled states.
Without timely feedback, users may repeat actions or assume that the application is broken.
Acknowledge user actions quickly
Show meaningful loading and progress states
Explain success and failure states clearly
type SubmitState =
| "idle"
| "submitting"
| "success"
| "error";
function SubmitButton({ state }: { state: SubmitState }) {
return (
<button
type="submit"
disabled={state === "submitting"}
>
{state === "submitting"
? "Saving..."
: "Save changes"}
</button>
);
}Good interfaces prevent avoidable mistakes before they happen and provide useful recovery paths when errors occur.
Error messages should explain what happened and what the user can do next rather than displaying vague technical failures.
Prevent errors when reasonable
Keep validation messages close to the relevant field
Provide a clear path to recovery
<label htmlFor="password">
Password
</label>
<input
id="password"
type="password"
aria-describedby="password-error"
aria-invalid="true"
/>
<p id="password-error" role="alert">
Password must contain at least 12 characters.
</p>Consistent components reduce the amount users need to relearn as they move through an application.
Design systems capture reusable decisions about colors, typography, spacing, components, interaction states, and patterns.
Use the same interaction pattern for the same behavior
Centralize reusable design decisions
Allow components to express meaningful variants instead of arbitrary styling
type ButtonProps = {
variant?: "primary" | "secondary" | "danger";
children: React.ReactNode;
};
export function Button({
variant = "primary",
children,
}: ButtonProps) {
return (
<button className={`button button--${variant}`}>
{children}
</button>
);
}Responsive design adapts content and controls to available space rather than shrinking a desktop interface until it fits.
Important content and actions should remain understandable and usable across screen sizes, zoom levels, and input methods.
Prioritize content instead of merely shrinking it
Allow layouts to reflow naturally
Design for touch, mouse, keyboard, and varying viewport sizes
.dashboard {
display: grid;
gap: 1rem;
}
@media (min-width: 48rem) {
.dashboard {
grid-template-columns:
minmax(0, 2fr)
minmax(16rem, 1fr);
}
}User-centered design begins with understanding the people who will use a product, the goals they are trying to achieve, and the context in which they perform those tasks.
Design decisions should be tested against real tasks and observable user behavior instead of relying entirely on assumptions.
Understand user goals before designing solutions
Test important workflows with representative users
Use observed problems to guide iteration
Weak framing:
"We need a larger dashboard."
User-centered framing:
"Users need to identify overdue tasks quickly
without scanning every project."
The second statement describes the problem
before prescribing the interface.