Learn how to organize content and navigation so users find what they need without conscious effort. Master card sorting to discover user mental models and tree testing to validate navigation structure before writing a single line of code.
Information architecture (IA) is the art and science of organizing content so that users can find it without consciously thinking about the structure. When IA is done well, users navigate a product as if reading their own mind. When done badly, users click through three menus, find nothing, and leave.
IA is invisible when it works. Nobody praises a supermarket for putting dairy near the back — they just find the milk. But every person who has entered a store where the layout made no sense has experienced bad IA: time wasted, frustration accumulated.
For developers, IA has a direct code counterpart: URL structure, routing hierarchy, and navigation components. A flat URL structure (/page1, /page2, /page3) reflects zero IA thinking. A nested, meaningful URL structure (/courses/javascript/react/hooks) reflects deep IA work. This lesson covers card sorting and tree testing — the two primary IA research methods — and shows how to translate their outputs into navigation code.
Peter Morville's Information Architecture discipline sits at the intersection of three forces: Users (what mental models and vocabulary do they bring?), Content (what information exists and what relationships does it have?), and Context (what is the business goal and what constraints exist?).
IA produces three concrete artifacts:
Miller's Law sets the cognitive limit: humans hold 7 plus or minus 2 items in working memory. Navigation menus with more than 7 items overload short-term memory. Keep each navigation level to 7 items maximum.
Good IA reflected in both site map and URL structure:
1Good: 5 items per level, clear hierarchy
2Home
3├── Courses (4 subcategories max)
4│ ├── Frontend
5│ ├── Backend
6│ ├── DevOps
7│ └── Data Science
8├── Guides
9├── Blog
10├── Pricing
11└── Community
12
13URLs: /courses/frontend/react/hooks
14 /courses/backend/nodejs/express
15
16Bad: 12 items at top level, no grouping
17Home Courses Tutorials Articles Videos Tools Templates Blog
18Jobs Community Forum Newsletter About Contact
19
20URLs: /content/c/789/l/234?cat=feURL structure is the most durable expression of your IA — it lives in bookmarks, emails, and search results for years. Get it right before you write the first route.
Card sorting is a research technique where users group labeled items into categories that make sense to them. The result reveals how users naturally organize your content — categories that feel intuitive to them, not just to you.
Open card sort: users create their own categories and name them. Use when you have no existing structure or want to discover unexpected groupings.
Closed card sort: users sort cards into predefined categories. Use to test whether your proposed categories are intuitive.
Running an open card sort:
Reading a similarity matrix:
If Redux and Zustand co-occur in the same group 91% of the time, users mentally categorize them as 'state management tools' — not just 'libraries.' Your navigation should have a 'State Management' category, not a generic 'Libraries' bucket.
Common card sort findings that change navigation design:
Card sort data → navigation label decision:
1<!-- Card sort finding: users grouped 'Guides' and 'Tutorials' together 87% of the time -->
2<!-- Decision: merge into one 'Guides' section, not two separate nav items -->
3<nav aria-label="Main navigation">
4 <ul role="list">
5 <li><a href="/courses">Courses</a></li>
6 <li><a href="/guides">Guides</a></li> <!-- was: Guides + Tutorials -->
7 <li><a href="/community">Community</a></li>
8 <li><a href="/pricing">Pricing</a></li>
9 </ul>
10</nav>Tree testing validates that users can find content in your proposed navigation structure — before writing any code. It is faster and cheaper than building the navigation and testing with real users afterward.
How tree testing works:
Key metrics:
Sample tree test result that changes design:
If only 40% of users navigate to 'Courses > By Topic > Frontend > React > Hooks' and 35% go to 'Courses > By Level > Beginner', your structure needs dual entry — listing courses under both topic AND difficulty. The tree test revealed the mental model mismatch before any code was written.
Implementing the validated IA in HTML with proper semantics:
1<!-- Skip link: critical for keyboard and screen reader users -->
2<a href="#main-content" class="skip-link">Skip to main content</a>
3
4<header>
5 <nav aria-label="Main navigation">
6 <ul role="list">
7 <li>
8 <!-- aria-current="page" marks the active page for screen readers -->
9 <a href="/courses" aria-current="page">Courses</a>
10 <ul role="list" aria-label="Course categories">
11 <li><a href="/courses/frontend">Frontend</a></li>
12 <li><a href="/courses/backend">Backend</a></li>
13 <li><a href="/courses/devops">DevOps</a></li>
14 </ul>
15 </li>
16 <li><a href="/guides">Guides</a></li>
17 <li><a href="/community">Community</a></li>
18 </ul>
19 </nav>
20</header>
21
22<main id="main-content">
23 <!-- page content -->
24</main>1/* Skip link — hidden until keyboard focus, essential for non-mouse users */
2.skip-link {
3 position: absolute;
4 top: -100%;
5 left: 1rem;
6 padding: 0.5rem 1rem;
7 background: #2563eb;
8 color: white;
9 border-radius: 0 0 0.5rem 0.5rem;
10 text-decoration: none;
11 font-weight: 600;
12 z-index: 9999;
13 transition: top 150ms ease;
14}
15.skip-link:focus { top: 0; }Once users are inside a navigation structure, they need wayfinding signals: where am I, where did I come from, how do I get back? The primary wayfinding pattern is the breadcrumb trail.
Breadcrumbs show the path from root to current page. They are essential for content deeper than two levels and reduce the need to use the browser back button.
Correct ARIA for breadcrumbs:
1<!-- Breadcrumb with correct ARIA semantics -->
2<nav aria-label="Breadcrumb">
3 <ol class="breadcrumb">
4 <li class="breadcrumb-item"><a href="/">Home</a></li>
5 <li class="breadcrumb-item"><a href="/courses">Courses</a></li>
6 <li class="breadcrumb-item"><a href="/courses/frontend">Frontend</a></li>
7 <li class="breadcrumb-item"><a href="/courses/frontend/react">React</a></li>
8 <li class="breadcrumb-item" aria-current="page">React Hooks Deep Dive</li>
9 </ol>
10</nav>1/* Breadcrumb CSS — separator via pseudo-element, not HTML entity */
2.breadcrumb {
3 display: flex;
4 flex-wrap: wrap;
5 list-style: none;
6 padding: 0;
7 margin: 0;
8 font-size: 0.875rem;
9 gap: 0;
10}
11.breadcrumb-item + .breadcrumb-item::before {
12 /* CSS content separator avoids cluttering HTML with visual symbols */
13 content: '\203A'; /* › right angle quotation mark */
14 margin: 0 0.5rem;
15 color: #9ca3af;
16 /* Decorative separator — screen readers should not read it */
17 aria-hidden: true;
18}
19.breadcrumb-item a {
20 color: #4b5563;
21 text-decoration: none;
22 transition: color 120ms ease;
23}
24.breadcrumb-item a:hover { color: #111827; text-decoration: underline; }
25.breadcrumb-item[aria-current="page"] { color: #111827; font-weight: 500; }A sticky header navigation implementing IA validated by card sorting and tree testing, with proper ARIA, keyboard support, and responsive behavior.
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Course Catalog — IA Implementation</title>
6 <style>
7 :root {
8 --nav-height: 3.5rem;
9 --nav-bg: #1e293b;
10 --nav-text: #e2e8f0;
11 --nav-hover-bg: #334155;
12 --accent: #3b82f6;
13 }
14 /* Skip link */
15 .skip-link {
16 position: absolute; top: -100%; left: 1rem;
17 padding: 0.5rem 1rem; background: var(--accent);
18 color: white; border-radius: 0 0 0.5rem 0.5rem;
19 text-decoration: none; font-weight: 600; z-index: 9999;
20 transition: top 150ms ease;
21 }
22 .skip-link:focus { top: 0; }
23 /* Header */
24 .site-header {
25 background: var(--nav-bg); height: var(--nav-height);
26 position: sticky; top: 0; z-index: 100;
27 box-shadow: 0 1px 3px rgb(0 0 0 / 0.3);
28 }
29 .nav-inner {
30 display: flex; align-items: center; height: 100%;
31 max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; gap: 2rem;
32 }
33 .site-logo { color: white; font-weight: 700; font-size: 1.125rem;
34 text-decoration: none; flex-shrink: 0; }
35 .main-nav > ul { display: flex; list-style: none; margin: 0; padding: 0; }
36 /* Nav items */
37 .nav-item { position: relative; }
38 .nav-link {
39 display: flex; align-items: center; gap: 0.375rem;
40 padding: 0 1rem; height: var(--nav-height);
41 color: var(--nav-text); text-decoration: none;
42 font-size: 0.9375rem; font-weight: 500; white-space: nowrap;
43 transition: background-color 150ms ease;
44 }
45 .nav-link:hover, .nav-link:focus { background: var(--nav-hover-bg); }
46 .nav-link[aria-current="page"] {
47 border-bottom: 2px solid var(--accent); color: white;
48 }
49 /* Dropdown */
50 .dropdown {
51 position: absolute; top: 100%; left: 0; min-width: 220px;
52 background: white; border-radius: 0.75rem;
53 box-shadow: 0 10px 40px rgb(0 0 0 / 0.15);
54 padding: 0.5rem;
55 opacity: 0; pointer-events: none;
56 transform: translateY(-8px);
57 transition: opacity 150ms ease, transform 150ms ease;
58 z-index: 10;
59 }
60 /* :focus-within handles keyboard navigation without JS */
61 .nav-item:hover .dropdown,
62 .nav-item:focus-within .dropdown {
63 opacity: 1; pointer-events: auto; transform: translateY(0);
64 }
65 .dropdown a {
66 display: block; padding: 0.5rem 0.75rem;
67 color: #374151; text-decoration: none;
68 border-radius: 0.5rem; font-size: 0.9375rem;
69 transition: background-color 100ms ease;
70 }
71 .dropdown a:hover { background: #f3f4f6; color: #111827; }
72 .dropdown-label {
73 font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
74 letter-spacing: 0.1em; color: #9ca3af;
75 padding: 0.5rem 0.75rem 0.25rem; margin-top: 0.25rem;
76 }
77 /* Breadcrumb */
78 .breadcrumb { display: flex; flex-wrap: wrap; list-style: none;
79 padding: 0; margin: 1.5rem 0 0; font-size: 0.875rem; }
80 .breadcrumb-item + .breadcrumb-item::before {
81 content: '\203A'; margin: 0 0.5rem; color: #9ca3af;
82 }
83 .breadcrumb-item a { color: #4b5563; text-decoration: none; }
84 .breadcrumb-item a:hover { color: #111827; text-decoration: underline; }
85 .breadcrumb-item[aria-current="page"] { color: #111827; font-weight: 500; }
86 </style>
87</head>
88<body>
89 <a href="#main" class="skip-link">Skip to main content</a>
90 <header class="site-header">
91 <div class="nav-inner">
92 <a href="/" class="site-logo">DevBootstrap</a>
93 <!-- Card sort: users grouped Frontend/Backend/DevOps/Data together -->
94 <!-- Tree test: 40% used Topic path, 35% used Level path — need both -->
95 <nav class="main-nav" aria-label="Main navigation">
96 <ul role="list">
97 <li class="nav-item">
98 <a href="/courses" class="nav-link" aria-haspopup="true">
99 Courses <span aria-hidden="true">▾</span>
100 </a>
101 <div class="dropdown" role="menu" aria-label="Browse courses">
102 <div class="dropdown-label">By Topic</div>
103 <a href="/courses/frontend" role="menuitem">Frontend Development</a>
104 <a href="/courses/backend" role="menuitem">Backend Development</a>
105 <a href="/courses/devops" role="menuitem">DevOps & Cloud</a>
106 <a href="/courses/data" role="menuitem">Data & Machine Learning</a>
107 <div class="dropdown-label">By Level</div>
108 <a href="/courses/beginner" role="menuitem">Beginner</a>
109 <a href="/courses/intermediate" role="menuitem">Intermediate</a>
110 <a href="/courses/advanced" role="menuitem">Advanced</a>
111 </div>
112 </li>
113 <li class="nav-item"><a href="/guides" class="nav-link">Guides</a></li>
114 <li class="nav-item"><a href="/community" class="nav-link">Community</a></li>
115 <li class="nav-item"><a href="/pricing" class="nav-link">Pricing</a></li>
116 </ul>
117 </nav>
118 </div>
119 </header>
120 <main id="main" style="max-width:1200px;margin:0 auto;padding:0 1.5rem;">
121 <nav aria-label="Breadcrumb">
122 <ol class="breadcrumb">
123 <li class="breadcrumb-item"><a href="/">Home</a></li>
124 <li class="breadcrumb-item"><a href="/courses">Courses</a></li>
125 <li class="breadcrumb-item"><a href="/courses/frontend">Frontend</a></li>
126 <li class="breadcrumb-item" aria-current="page">React</li>
127 </ol>
128 </nav>
129 <h1>React Courses</h1>
130 </main>
131</body>
132</html>The navigation implements IA derived from research: card sorting showed users grouped courses by both Topic and Level (87% and 73% co-occurrence respectively), and tree testing showed 40% navigated by topic while 35% navigated by level — so the dropdown provides both paths. The skip link enables keyboard bypass. The dropdown works via CSS :focus-within without JavaScript, making it keyboard-accessible. The breadcrumb uses proper ARIA semantics (aria-label="Breadcrumb", aria-current="page"). Every structural decision traces directly to a research finding.
The next lesson covers wireframing — the art of rapidly sketching interface layouts that test your information architecture decisions and communication flows before committing to high-fidelity visual design.
Your progress is saved in this browser, on this device only.