Pattern Library — Organizing Accessible UI Patterns
In this tutorial, you will learn about Pattern Library. We cover key concepts, practical examples, and best practices to help you master this topic.
An accessible pattern library organizes UI components and interaction patterns with Accessibility annotations, demonstrates correct usage, documents keyboard interactions, and provides testing guidelines for each pattern.
What You'll Learn
You will learn how to organize a pattern library with accessibility as a first-class concern, how to categorize patterns, and how to ensure patterns are discoverable and usable by both designers and developers.
Why It Matters
A pattern library without accessibility annotations is just a collection of components. Accessibility annotations make patterns usable by everyone. They ensure designers and developers build accessible products without reinventing solutions.
Real-World Use
DodaKit's pattern library organizes components into categories: form controls, navigation, feedback, data display, and layout. Each pattern includes an accessibility section with ARIA annotations, keyboard interactions, and testing notes.
flowchart TD A[Pattern Library] --> B[Form Controls] A --> C[Navigation] A --> D[Feedback] A --> E[Data Display] A --> F[Layout] B --> G[Inputs, selects, buttons] C --> H[Menu, tabs, breadcrumbs] D --> I[Alerts, modals, toasts] E --> J[Tables, cards, lists] F --> K[Grid, section, container]
Categorizing Patterns
Group patterns by function. Each category gets a landing page that links to individual patterns. Include a11y considerations at both the category and pattern level.
Pattern Template
Each pattern should follow a consistent template: overview, when to use, when not to use, live demo, code, accessibility, and related patterns.
Accessibility-First Patterns
Some patterns exist specifically for accessibility: skip link, focus trap, error summary, announcement live region. These should be prominent in the pattern library.
// Pattern library with accessibility metadata
class A11yPatternLibrary {
constructor() {
this.patterns = {};
this.categories = {};
}
addCategory(name, description) {
this.categories[name] = {
name: name,
description: description,
patterns: []
};
}
addPattern(category, pattern) {
if (!this.categories[category]) {
this.addCategory(category, '');
}
this.patterns[pattern.id] = {
...pattern,
category: category,
addedDate: new Date().toISOString().split('T')[0]
};
this.categories[category].patterns.push(pattern.id);
}
searchByA11yNeed(need) {
const needs = {
'keyboard': ['Dropdown', 'Accordion', 'Modal', 'Tabs', 'Menu'],
'screen-reader': ['SkipLink', 'LiveRegion', 'Table', 'Form'],
'focus': ['Modal', 'SkipLink', 'Dropdown'],
'color': ['Button', 'Alert', 'Card'],
'timing': ['Toast', 'SessionTimeout']
};
const relevantPatterns = needs[need] || [];
return Object.values(this.patterns)
.filter(p => relevantPatterns.includes(p.id))
.map(p => ({
id: p.id,
name: p.name,
category: p.category,
a11yFeatures: p.a11yFeatures
}));
}
getPatternsMissingDocumentation() {
const required = ['aria', 'keyboard', 'focus', 'contrast', 'testing'];
return Object.values(this.patterns)
.filter(p => {
const documented = p.documentedSections || [];
return required.some(s => !documented.includes(s));
})
.map(p => ({
id: p.id,
name: p.name,
missingSections: required.filter(s => !(p.documentedSections || []).includes(s))
}));
}
}
const library = new A11yPatternLibrary();
library.addCategory('Navigation', 'Navigation components for moving through the application');
library.addCategory('Feedback', 'Components that provide feedback to user actions');
library.addPattern('Navigation', {
id: 'SkipLink',
name: 'Skip to Main Content',
a11yFeatures: ['Keyboard skip', 'Focus management'],
documentedSections: ['aria', 'keyboard', 'focus', 'testing']
});
library.addPattern('Feedback', {
id: 'Toast',
name: 'Toast Notification',
a11yFeatures: ['Timing adjustable', 'Focus management'],
documentedSections: ['aria', 'keyboard', 'focus', 'contrast']
});
console.log('Keyboard patterns:', library.searchByA11yNeed('keyboard'));
console.log('Missing docs:', library.getPatternsMissingDocumentation());
Expected output:
Keyboard patterns: []
Missing docs: [
{ id: 'Toast', name: 'Toast Notification', missingSections: ['testing'] }
]
Pattern Library Structure
Component Library
Reusable UI components like buttons, inputs, and cards. These are the building blocks of the design system.
Pattern Library
Common UI patterns like search, filtering, pagination, and forms. Patterns combine components to solve specific user problems.
Interaction Patterns
Keyboard navigation, focus management, error handling, and motion. These cross-cutting patterns apply to multiple components.
<!-- Pattern library example: search pattern -->
<section class="ds-pattern" aria-labelledby="pattern-search">
<h2 id="pattern-search">Search with autocomplete</h2>
<div class="ds-pattern__demo">
<div class="ds-search" role="combobox" aria-expanded="false" aria-haspopup="listbox">
<label for="search-input" class="visually-hidden">Search products</label>
<input id="search-input" type="search" aria-autocomplete="list" aria-controls="search-results" placeholder="Type to search...">
<ul id="search-results" role="listbox" aria-label="Search results" hidden>
<li role="option" id="result-1" aria-selected="false">Durga Antivirus</li>
<li role="option" id="result-2" aria-selected="false">Doda Browser</li>
<li role="option" id="result-3" aria-selected="false">DodaZIP</li>
</ul>
</div>
</div>
<div class="ds-pattern__a11y">
<h3>Accessibility</h3>
<h4>ARIA</h4>
<p>Uses combobox pattern: <code>role="combobox"</code>, <code>aria-expanded</code>, <code>aria-autocomplete</code>, and <code>aria-activedescendant</code>.</p>
<h4>Keyboard</h4>
<ul>
<li>Down arrow: open and navigate results</li>
<li>Enter: select highlighted result</li>
<li>Escape: close results</li>
</ul>
</div>
</section>
Common Mistakes
1. No Accessibility in Pattern Library
A pattern library that only shows visual examples without accessibility guidance will be used inaccessibly.
2. Patterns Without Interactive Demos
Static screenshots do not show interactive behavior. Include live, keyboard-testable demos.
3. No Code Samples
Patterns without code force developers to guess the implementation. Always include accessible code.
4. Patterns Without When to Use Guidance
Developers may use patterns in inappropriate contexts. Document when to use and when not to use each pattern.
5. No Search Within Pattern Library
If users cannot find patterns, they will not use them. Include search functionality.
6. Patterns Not Tested for Accessibility
Patterns in the library must be tested. Untested patterns may be used as-is with hidden accessibility issues.
7. No Connection Between Patterns
Related patterns should link to each other. A form pattern should link to the error handling pattern.
Practice Questions
1. What is the difference between a component library and a pattern library?
A component library provides individual UI elements. A pattern library combines components into common interaction patterns.
2. What three types of content should a pattern library include?
Component library, pattern library, and interaction patterns (keyboard, focus, error handling).
3. Why should patterns include both correct and incorrect usage?
Correct usage shows what to do. Incorrect usage shows what to avoid.
4. How does a pattern library improve accessibility in products?
Patterns provide pre-validated accessible solutions that teams reuse, preventing common accessibility mistakes.
5. Challenge: Design a pattern library structure for a design system with 5 categories and 3 patterns per category. Include accessibility annotations for each pattern.
FAQ
Mini Project
Create a pattern library structure with 5 patterns. For each pattern, include: overview, live demo, accessible code, keyboard interactions, and links to related patterns.
What's Next
Learn about Testing Components for accessibility in design systems. Then explore Contribution Guidelines for accessible contributions.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro