Skip to main content
New: Forge AI docs + Loop PM assistant. 7-day free trial.
TemplateFREE⏱️ 45-60 minutes

Component Spec Template

A structured template for specifying individual UI components. Covers anatomy, states, variants, behavior, accessibility requirements, and edge cases with a filled example for a multi-select dropdown.

By Tim Adair• Last updated 2026-03-05
Component Spec Template preview

Component Spec Template

Free Component Spec Template — open and start using immediately

or use email

Instant access. No spam.

What This Template Is For

A component spec is the definitive reference for how a single UI element works. It documents every state, variant, interaction, and edge case so designers and engineers build the same thing without ambiguity. The spec answers questions that mockups cannot: What happens when the label text is 200 characters long? What does the error state look like? What keyboard shortcuts does this support? How does it behave on a 320px screen?

Most component bugs trace back to unspecified states. The designer delivered a mockup showing the default and hover state, but nobody defined the disabled state, the loading state, the error state, or the overflow behavior. The engineer made reasonable guesses. The PM filed bugs because the guesses did not match the intended behavior. The component spec prevents this cycle by forcing every state to be explicitly defined before implementation begins.

This template works for any reusable UI element: buttons, inputs, dropdowns, modals, cards, tables, navigation items, and custom components. It pairs well with the design system documentation template for cataloging components as part of a broader system. For teams running formal handoff reviews, the design review template provides a structured checkpoint to validate the spec before engineering starts. Understanding the concept of cognitive load helps PMs make better decisions about component complexity and when to simplify.


How to Use This Template

  1. Start with the Component Overview. Name the component, describe its purpose in one sentence, and list where it appears in the product. This anchors the spec in real usage rather than abstract component theory.
  2. Draw the anatomy diagram. Label every visual element of the component: icon, label, helper text, border, background, indicator. This creates a shared naming convention between design and engineering.
  3. Define all states. Most interactive components have at least 6 states: default, hover, focus, active/pressed, disabled, and error. Some have loading, selected, and read-only states as well. For each state, specify the visual treatment and any behavioral changes.
  4. Define all variants. Size variants (small, medium, large), style variants (primary, secondary, ghost), and context variants (inline, standalone) should each be documented with their use cases.
  5. Specify interaction behavior: click, keyboard, touch, and screen reader interactions. Include tab order, arrow key behavior, and ARIA attributes.
  6. Document edge cases. What happens with very long text? What about empty data? RTL languages? High contrast mode? The edge cases section prevents the most common implementation surprises.

The Template

Component Overview

FieldDetails
Component Name[Name as it appears in code and design system]
Purpose[One sentence: what user need does this component serve?]
Usage Locations[List screens/features where this component appears]
Related Components[Components this extends, wraps, or is often used with]
Design System StatusDraft / In Review / Approved / Implemented

Anatomy

Label every distinct visual element of the component.

 ┌─────────────────────────────┐
 │  [Icon]  [Label]     [▼]   │  ← Container
 │                             │
 │  [Helper text]              │  ← Supporting text
 └─────────────────────────────┘
ElementRequiredDescription
ContainerYes[Dimensions, padding, border, background]
IconNo[Leading icon, size, color]
LabelYes[Typography token, color, truncation behavior]
IndicatorYes[Chevron, arrow, or state indicator]
Helper textNo[Supporting text below the component]

States

StateVisual TreatmentBehavior
Default[Border, background, text color][Clickable, awaiting interaction]
Hover[Border change, background change, cursor][Visual feedback on pointer enter]
Focus[Focus ring style, outline offset][Keyboard focus indicator visible]
Active / Pressed[Background darkens, slight scale][Visual feedback during click/tap]
Disabled[Opacity reduction, cursor not-allowed][Not interactive, skip in tab order]
Error[Red border, error icon, error message][Validation failure state]
Loading[Spinner or skeleton, reduced opacity][Awaiting data, not interactive]
Read-only[Muted styling, no interaction affordance][Displays value but cannot be changed]

Variants

VariantUse CaseVisual Difference
Size: SmallDense layouts, tables, toolbars[Height, padding, font size]
Size: MediumDefault for most forms[Height, padding, font size]
Size: LargePrimary actions, onboarding[Height, padding, font size]
Style: PrimaryMain action, high emphasis[Fill color, text color]
Style: SecondarySupporting action, medium emphasis[Outline style, text color]
Style: GhostTertiary action, low emphasis[No border, text-only]

Interaction Behavior

Mouse / Touch:

  • Click triggers [action]
  • Hover shows [visual feedback]
  • Long press triggers [action, if applicable]
  • Drag behavior: [none / reorderable / resizable]

Keyboard:

  • Tab moves focus to/from the component
  • Enter or Space triggers the primary action
  • Escape closes/dismisses (if applicable)
  • Arrow keys [behavior if applicable]
  • Type-ahead search [if applicable]

Screen Reader:

  • ARIA role: [button / combobox / listbox / etc.]
  • ARIA label: [How the component is announced]
  • ARIA expanded/selected/checked: [State announcements]
  • Live region: [For dynamic content changes]

Responsive Behavior

BreakpointBehavior
Mobile (< 640px)[Full width, stacked layout, touch target 44px minimum]
Tablet (640-1024px)[Behavior]
Desktop (> 1024px)[Default behavior as specified above]

Edge Cases

CaseExpected Behavior
Label text exceeds container width[Truncate with ellipsis / wrap to multiple lines / tooltip on hover]
Empty data / no options[Show empty state message / disable component]
Very long list of items[Virtual scrolling / max-height with scroll / search filter]
RTL language[Mirror layout, preserve icon positions]
High contrast mode[Borders visible, focus ring meets contrast ratio]
Slow network[Loading skeleton for async data]

Design Tokens

PropertyTokenValue
Border radius--radius-md[Value]
Border color (default)--border-default[Value]
Border color (focus)--border-focus[Value]
Background (default)--bg-input[Value]
Text color--text-primary[Value]
Font size--text-sm[Value]
Padding--space-2 --space-3[Value]
Transition--duration-fast --ease-standard[Value]

Filled Example: Multi-Select Dropdown

Component Overview

FieldDetails
Component NameMultiSelect
PurposeAllow users to select one or more options from a filterable dropdown list
Usage LocationsFilter bars, form fields (assign team members, select tags), settings pages
Related ComponentsSelect (single), Combobox, Checkbox, Tag/Chip
Design System StatusIn Review

Anatomy

 ┌──────────────────────────────────────┐
 │  [Tag] [Tag] [Tag]  [input] [Clear ✕]│  ← Container (selected tags + input)
 └──────────────────────────────────────┘
 ┌──────────────────────────────────────┐
 │  🔍 [Search input]                   │  ← Dropdown header
 ├──────────────────────────────────────┤
 │  ☑ Option A                          │  ← Selected option
 │  ☐ Option B                          │  ← Unselected option
 │  ☐ Option C                          │  ← Unselected option
 │  ☑ Option D                          │  ← Selected option
 ├──────────────────────────────────────┤
 │  3 of 12 selected                    │  ← Footer (count)
 └──────────────────────────────────────┘
ElementRequiredDescription
ContainerYes40px height (medium), 8px padding, 1px border, grows to wrap tags
Selected tagsConditionalCyan pill with "x" remove button, max 3 visible + "+N more"
Text inputYesInline input for type-ahead filtering, placeholder: "Select..."
Clear buttonConditional"x" icon at right edge when 1+ items selected
Dropdown panelConditionalOpens below container, max-height 280px, scrollable
Search inputYesPinned at top of dropdown, does not scroll with options
Option rowYes36px height, checkbox + label, hover highlight
FooterOptionalShows "N of M selected" when list exceeds 10 items

States

StateVisual TreatmentBehavior
DefaultGray border, "Select..." placeholderClick opens dropdown
HoverBorder darkens to gray-400Cursor changes to pointer
Focus2px cyan focus ring, offset 2pxDropdown opens on focus (optional: only on Enter)
OpenCyan border, dropdown visible, shadow-lgType-ahead filters options in real time
Disabled50% opacity, cursor not-allowedNo interaction. Selected values still visible but not editable
ErrorRed border, red helper text below"Please select at least one option" (or custom message)
LoadingSpinner replaces chevron, "Loading..." in dropdownOptions fetched asynchronously
Read-onlyNo border, tags displayed as static textValues visible but not clickable

Variants

VariantUse CaseVisual Difference
Size: SmallTable cells, dense filter bars32px height, 12px text, max 2 tags visible
Size: MediumStandard forms40px height, 14px text, max 3 tags visible
Size: LargePrimary forms, onboarding48px height, 16px text, max 4 tags visible
CreatableTag management, flexible inputsShows "Create [typed value]" option when no match found

Interaction Behavior

Mouse / Touch:

  • Click on container opens dropdown, focuses search input
  • Click on option toggles selection (checkbox updates, tag added/removed)
  • Click on tag "x" removes that selection
  • Click on clear button removes all selections
  • Click outside dropdown closes it, preserving selections

Keyboard:

  • Tab focuses the container. Second Tab moves past the component
  • Enter or Space on container opens dropdown
  • Arrow keys navigate options within the open dropdown
  • Enter or Space on an option toggles its selection
  • Escape closes dropdown without changing selections
  • Backspace on empty input removes the last selected tag
  • Typing filters the option list (type-ahead search)

Screen Reader:

  • ARIA role: combobox on container, listbox on dropdown, option on each row
  • ARIA label: "[Field label], multi-select, N items selected"
  • aria-expanded="true/false" on container reflecting dropdown state
  • aria-selected="true/false" on each option
  • aria-activedescendant updates as arrow keys move focus within dropdown
  • Live region announces selection changes: "Option A selected. 3 of 12 selected."

Edge Cases

CaseExpected Behavior
50+ selected itemsShow first 3 tags + "+47 more" badge. Tooltip on badge shows full list
Option label > 60 charactersTruncate with ellipsis in dropdown. Full text in tooltip on hover
0 options availableShow "No options available" in dropdown body. Disable search input
Search returns no matchesShow "No results for '[query]'" with clear search button
All options selectedShow "All selected" in footer. Disable search input
Async load failureShow "Failed to load options. Retry." with retry button in dropdown
Form submission with 0 selectionsBlock submit if required. Show error state with helper text

Common Mistakes to Avoid

  • Documenting only the happy path. The default and hover states are the easy ones. The bugs live in error, loading, disabled, overflow, and empty states. Spec every state explicitly. Use the usability testing process to validate that edge cases work before launch.
  • Skipping keyboard behavior. Every interactive component must be fully operable by keyboard. This is not a nice-to-have. It is a WCAG requirement and a legal obligation in many markets.
  • Defining variants without use cases. Three size variants and four style variants create 12 combinations. If you cannot name a real screen where each combination appears, you are building unused complexity. Start with the variants you need today.
  • Using screenshots instead of specs. Screenshots show one state at one viewport width. They cannot communicate transitions, keyboard behavior, overflow handling, or responsive behavior. Screenshots are supplements to a spec, not substitutes.
  • Not defining the token contract. If the spec says "gray border" instead of referencing a design token (--border-default), the engineer will pick a gray hex value that does not match the system. Always reference tokens.

Key Takeaways

  • Spec every state explicitly: default, hover, focus, active, disabled, error, loading, and read-only
  • Define keyboard and screen reader behavior as first-class requirements, not afterthoughts
  • Document edge cases (overflow, empty data, async failure) to prevent implementation guesswork
  • Reference design tokens by name, not by raw color or size values
  • Include filled examples with real product scenarios to make the spec concrete

About This Template

Created by: Tim Adair

Last Updated: 3/5/2026

Version: 1.0.0

License: Free for personal and commercial use

Frequently Asked Questions

How detailed should a component spec be for a simple button?+
Even a simple button has more states than most teams realize: default, hover, focus, active, disabled, loading, and icon-only variants. A button spec should be shorter than this multi-select example, but it still needs to cover every state, size variant, and keyboard behavior. For common components, reference the [design system documentation template](/templates/design-system-documentation-template) and keep individual specs lightweight by inheriting global conventions.
Who writes the component spec?+
Usually the designer writes it, with input from the PM (on use cases and edge cases) and the engineer (on technical constraints). The PM should review the spec to confirm it covers the product requirements and user scenarios they care about. The engineer should review to confirm it is implementable within technical constraints.
When should I write a spec vs. just using Figma inspection?+
Write a spec when the component has complex interaction behavior (keyboard shortcuts, multi-step flows, async loading), multiple states, or will be reused across the product. Simple, one-off UI elements (a static card, a text block) usually do not need a formal spec. Figma inspection is sufficient for visual properties but cannot communicate behavior.
How do I handle responsive behavior for custom components?+
Define breakpoints in the Responsive Behavior section. For each breakpoint, describe what changes: does the component switch from inline to full-width? Do touch targets increase? Does the layout stack vertically? If the component is not usable below a certain width, say so explicitly and define the minimum supported width. ---

Explore More Templates

Browse our full library of AI-enhanced product management templates

Free PDF

Like This Template?

Subscribe to get new templates, frameworks, and PM strategies delivered to your inbox.

or use email

Instant PDF download. One email per week after that.

Want full SaaS idea playbooks with market research?

Explore Ideas Pro →