← Blog
12 Sept 2026design system componentsUI componentsdesign systemscomponent libraryVue components

Design System Components Explained with Real Examples

Learn what design system components are, how they work, and how to build, govern and scale them — with real examples and best practices.

Design System Components Explained with Real Examples

Your team has three versions of the same button, two form patterns, and a handoff that keeps bouncing between design and development. One button changes colour on a different screen, one form field handles errors differently, and nobody knows which implementation should become the standard. Delivery slows down, not because the interface is unusually complex, but because familiar interface decisions keep being remade.

Design system components address that repetition. They package a shared interface decision into something teams can use, understand, test, and improve. A good component isn’t just a styled rectangle in a design file or a component-library export. It combines structure, visual decisions, behaviour, accessibility requirements, documentation, and a usable API.

The GOV.UK Design System provides a useful public-sector example. It was formally introduced on 22 June 2018 as a central place for government teams to find styles, components, and patterns for user-centred digital services, bringing together material from the Service Manual, GOV.UK Elements, and other sources (GOV.UK Design System launch announcement). The important shift wasn’t the publication of buttons and checkboxes. It was the move from scattered interface assets towards a shared model for building services.

This guide moves from the inside out. You’ll start with what a component is, then examine its anatomy, learn how to document it, compare headless primitives with styled wrappers, and finish with the governance practices that keep a library dependable as more teams adopt it.

By the end, you’ll be able to evaluate an existing component, identify gaps in its API and accessibility behaviour, choose an integration pattern that suits your stack, and create a practical route for scaling a component library without turning it into a collection of disconnected code.

Table of Contents

Introduction to Design System Components

A component library often starts with good intentions. A designer creates a button set, a developer turns it into a reusable component, and the team publishes it in Storybook or an internal package. Later, another product needs a destructive action, so someone adds a new colour. A third team needs an icon-only button, so it adds another prop. A form component then grows its own error treatment, focus style, and label spacing.

None of those changes looks dangerous in isolation. The problem appears when users move between products and encounter different interaction rules for the same task. Developers also pay the cost. They need to remember which component supports which prop, whether a disabled state is disabled, and whether a dialog traps focus correctly or only looks like it does.

A design system component turns a repeated decision into a shared contract. That contract should answer several questions:

  • What does it render? The underlying HTML should reflect the element’s meaning.
  • What can change? Props, attributes, slots, and composition rules define the supported API.
  • How does it behave? Keyboard interaction, focus movement, validation, and state transitions need explicit rules.
  • How should teams use it? Guidance should cover suitable contexts, alternatives, and common mistakes.
  • How will it remain healthy? Ownership, testing, release notes, and deprecation rules belong to the system too.

The value is broader than visual consistency. Reuse gives teams a common starting point, while shared guidance helps them avoid repeating accessibility and interaction mistakes. The GOV.UK Design System describes components as reusable UI parts and explains that pre-built core elements help teams build consistent services (GOV.UK Design System). It also makes an important qualification: reuse alone doesn’t make a service accessible.

That qualification should shape how you work. A button component can centralise semantics and focus styling, but the team still needs to test the component in real interfaces. A form field can provide an error slot, but the product still needs useful error content. A dialog can manage focus, but the surrounding application must decide when opening it is appropriate.

The progression is straightforward: understand the component’s parts, make each part explicit, select an integration model, and govern the result as a product rather than a static asset.

What Design System Components Are and How They Work

Think of a component as a LEGO brick with an instruction sheet and a quality standard. The brick has a shape, connection points, and a purpose. The instructions explain how to use it. The quality standard defines what must be true before the brick can be added to the shared box.

In interface work, the equivalent parts are:

  1. Structure, usually semantic HTML and the DOM relationship between elements.
  2. Styles, including colour, spacing, typography, borders, and responsive rules.
  3. Behaviour, such as opening a menu, moving focus, or submitting a form.
  4. API, the props, attributes, events, slots, and exposed methods that consumers use.
  5. Guidance, which tells people when to use the component and what to avoid.

A button is a primitive component. A field with a label, hint, input, and error message is a composite component. A form section that combines several fields with validation and submission rules is closer to a pattern. These layers are related, but they shouldn’t be forced into one giant component. A primitive should solve a focused problem. Composition should handle the larger experience.

A diagram illustrating the anatomy of a button component, highlighting structure, props, design tokens, behavior, and variants.

The layers around a component

Design tokens name shared decisions such as a surface colour, spacing value, type style, or focus-ring treatment. Components consume those decisions instead of embedding unrelated values throughout their CSS. Tokens make a change traceable. If the focus treatment changes, the system can identify which components depend on that decision.

Variants expose intentional differences. A button might offer primary, secondary, and destructive variants. A menu might have a compact presentation for a toolbar. Variants should represent meaningful product decisions, not every possible combination of CSS properties.

States describe what users can encounter during interaction. Hover is only one state. Focus, pressed, expanded, selected, loading, invalid, and disabled states may matter more for keyboard and assistive-technology users than the default appearance.

A style guide usually shows visual rules. A component library usually supplies code. A design system component connects both with behaviour and guidance. That connection is what makes the system useful across teams. For a wider explanation of how reusable systems support speed and scale with design systems, it’s helpful to look beyond individual UI files and consider the operating model around them.

The GOV.UK example demonstrates this at national scale. By 31 March 2022, its Design System reported 32 styles, components, or patterns added or improved, code reused more than 3,300 times, and more than 2,700,000 downloads of the GOV.UK Frontend package (GOV.UK Design System update). Those figures don’t prove that every service used every component correctly. They do show how a shared component model can become an operational practice rather than a design aspiration.

Anatomy of a Component From Props to Variants

A reliable component specification describes more than its appearance. Start with a button, then inspect the decisions hidden inside it.

Structure comes first

Use the native element that matches the action. A button that triggers an operation should render a real button. A link that moves the user to another place should render an a with an href. If a custom element wraps either one, the internal markup still needs to preserve the correct semantics.

This distinction affects keyboard behaviour, browser defaults, form submission, focus, and assistive technology. Replacing a native element with a generic container creates work that the platform already solved.

Props define the public contract

Props should answer a consumer’s practical questions without exposing implementation details. A button API might include:

  • variant, for an intentional visual and semantic emphasis
  • disabled, for unavailable interaction
  • type, such as button or submit
  • loading, when the application needs to communicate an in-progress action
  • href, only if the component has a deliberate link mode

Avoid a prop for every visual adjustment. If consumers can choose arbitrary padding, border thickness, colour, and font weight, the component no longer provides a coherent design decision. Use slots where content needs to remain flexible, and use composition where the consumer needs to assemble a larger pattern.

Variants and states need boundaries

A variant is a supported mode. A state is a condition the component enters during use. Mixing the two creates confusing APIs. “Danger” describes intent. “Pressed” describes interaction. “Invalid” describes a form condition. Each should have clear styling, behaviour, and documentation.

The same distinction applies to a dialog. Its API might expose an open state, a title slot, a description slot, and actions. Its behaviour needs to define what happens when a user presses Escape, where focus goes when the dialog opens, and where focus returns after it closes. The component shouldn’t invent application state or decide whether a user may dismiss a critical confirmation.

Tokens and theming hooks connect design to code

A component can consume global tokens while exposing a small set of local custom properties. The global layer gives the system consistency. The local layer gives a theme or product a controlled extension point.

For example, a button might use a shared text colour token and map it to a component-level property for its destructive variant. That arrangement lets the theme change the underlying colour decision without forcing consumers to replace the component’s internal selectors.

An infographic listing five best practices for design and documentation including consistency, tokens, accessibility, states, and guidelines.

Specification test: If a developer can’t tell which HTML element, prop value, event, and state apply to an example, the component API isn’t finished.

A useful specification records the DOM structure, supported inputs, emitted events, state transitions, token dependencies, accessibility requirements, and examples. It should also say what the component doesn’t support. Constraints prevent teams from treating every new request as a reason to add another escape hatch.

Best Practices for Designing and Documenting Components

Durable components come from disciplined decisions before the code becomes difficult to change. Start with the name. A predictable naming scheme helps users find related components and stops two teams from publishing different meanings under similar labels. Choose whether your system uses names such as Button, DomButton, or custom elements such as ds-button, then apply the rule consistently.

Keep the API small enough to understand. A variant property is often more useful than several style booleans, but even variants need limits. Prefer a controlled set of values when the design decision is part of the system. Provide an escape hatch only when the use case is legitimate and the escape hatch won’t leak internal implementation details.

Build accessibility into the default path

Accessibility needs to be part of the component’s first implementation, not a later audit. Use semantic HTML where native behaviour meets the requirement. Add ARIA only when it communicates a relationship or state that HTML alone can’t express. For composite widgets, define keyboard behaviour and focus management as part of the component contract.

The GOV.UK Design System warns that reusable components don’t automatically make a service accessible. Its guidance points teams towards semantic HTML, content that remains available without CSS, and JavaScript-free fallbacks where appropriate (GOV.UK accessibility guidance). The system’s documentation and GOV.UK Frontend are stated to be compliant with WCAG 2.2 AA, and the team regularly tests common assistive-technology and browser combinations (GOV.UK accessibility statement). That baseline is valuable, but the same statement also identifies edge cases, including limitations involving the details component with Dragon and older VoiceOver versions.

Document the decision, not only the syntax

A code example shows how to render a component. Good documentation also explains when to use it, when not to use it, which state appears after an action, and what content belongs in each slot.

Include:

  • A working example, so users can inspect the rendered result.
  • The API, including types, defaults, events, slots, and restrictions.
  • State coverage, including focus, invalid, loading, expanded, selected, and disabled states where relevant.
  • Do and don’t guidance, tied to real interface decisions.
  • Accessibility notes, including keyboard expectations and labelling requirements.
  • Migration information, when a release changes markup, props, or behaviour.

For a practical approach to keeping implementation details and usage guidance together, see design system documentation. Documentation should live close enough to the component that a change naturally prompts a documentation update.

An infographic titled Best Practices for Designing and Documenting Components featuring ten key tips for component design.

Finally, test the package in the environments where teams will use it. Keep modules tree-shakeable where possible, avoid forcing consumers to load unrelated components, and make framework boundaries explicit. A component that looks elegant in a single demo but adds hidden coupling to every application isn’t a durable building block.

Integration Patterns Including Headless Primitives and Vue Wrappers

The implementation choice changes how a team consumes a component, but it shouldn’t change the component’s fundamental contract. Three patterns appear frequently.

A headless primitive supplies behaviour, semantics, and accessibility without imposing a finished visual style. It might manage an expanded state, connect a trigger to a popup, and handle keyboard input while leaving colour, spacing, and typography to the consuming application.

A styled wrapper packages the same interaction with a visual treatment. It can be quicker for teams that want a ready-made interface, but it creates stronger opinions about markup, tokens, CSS, and theming.

A framework binding adapts the primitive for a particular development model. In Vue, a thin wrapper can add reactive props, v-model, slots, and event conventions without rewriting the underlying interaction logic. That distinction matters. The wrapper should improve developer experience, not become a second, divergent implementation.

Screenshot from https://getdom.studio

Choose based on the boundary you need

Pattern Best For Trade-off
Headless web component primitive Multiple frameworks, custom visual systems, long-lived platform code Consumers own more styling and visual composition
Styled wrapper Teams that need a consistent interface with limited setup The wrapper can make theming and framework changes harder
Vue binding over a primitive Vue teams that want reactivity, slots, and familiar APIs The binding adds a framework-specific layer to maintain

Custom elements work well when portability is a priority. They can act as a stable browser-facing boundary, while application code handles business state and product-specific composition. This keeps a dialog primitive focused on focus, dismissal, and relationships rather than embedding an application’s permissions or data-fetching logic.

Vue wrappers make sense when the team benefits from Vue’s reactive conventions. A v-model binding can express open state clearly, and slots can make a compound component pleasant to compose. The wrapper should still pass through the important accessibility and interaction behaviour rather than replacing it with a visual-only abstraction.

DOM Studio illustrates this hybrid pattern through headless web component primitives and a thin Vue integration layer. Its documented approach combines standards-based custom elements with Vue-oriented props, v-model support, slots, and Tailwind CSS 4 styling. Teams evaluating that model can compare it with other options using the criteria in headless UI component library, especially where framework portability and custom theming need to coexist.

The following video provides another way to inspect the integration approach. Watch how the primitive and the consuming interface relate before deciding where your own application state should live.

For AI-ready systems, explicit APIs and inspectable component metadata matter as much as visual flexibility. Generated code is easier to correct when the component exposes clear props, slots, states, and usage rules instead of hiding behaviour behind opaque application code.

Real Examples Governance and Scaling Your System

A component library becomes a design system when people can rely on it over time. GOV.UK offers a useful example because its launch consolidated patterns and code that had previously lived in several places. Its later update recorded reuse and package downloads, showing how a central source can support repeated delivery across a large organisation.

The lesson isn’t to copy GOV.UK’s visual language. The lesson is to make ownership and reuse visible. A library should tell teams which component is supported, who reviews changes, what alternatives exist, and how a breaking change will be handled.

A catalogue needs more than a component list

A mature catalogue might contain buttons, menus, listboxes, dialogs, tabs, drawers, accordions, comboboxes, and command palettes. Each item needs a clear boundary. A menu shouldn’t become a command palette because both contain selectable rows. A dialog shouldn’t own application navigation because it happens to contain links.

For every component, define:

  • Ownership, including maintainers and contribution routes.
  • Status, such as experimental, supported, or deprecated.
  • Compatibility, including framework and browser expectations.
  • Release policy, covering additive changes, bug fixes, and breaking changes.
  • Migration guidance, with replacement examples and codemods where practical.
  • Evidence, including automated tests, accessibility checks, and visual review.

Governance is a product workflow

A contribution process should let teams propose a missing component without allowing every local preference into the core. Ask for the user problem, existing alternatives, expected consumers, accessibility requirements, and maintenance cost. Review the API and interaction model before investing in a polished visual treatment.

Versioning then gives consumers a predictable way to adopt change. Deprecation should be deliberate and visible. Keep an old component long enough for teams to migrate, explain the replacement, and remove obsolete paths only when the cost of retaining them outweighs the migration risk.

The GOV.UK accessibility statement is a useful reminder that compliance doesn’t eliminate real-world testing. A system can establish a baseline while still documenting assistive-technology edge cases. Your own governance should make those limitations discoverable instead of presenting the library as universally correct.

For a deeper operational view of contribution, release, theming, and migration, use design system governance as a reference point. Startups may handle these responsibilities in one shared repository. Enterprise teams may need a formal working group, but the underlying questions remain the same: who decides, how do consumers know, and what happens when a component needs to change?

Conclusion and Next Steps for Your Component Library

Strong design system components are small enough to understand and substantial enough to carry a real contract. Their anatomy includes semantic structure, a constrained API, meaningful variants, explicit states, token connections, behaviour, accessibility requirements, and documentation. Their value appears when teams can reuse those decisions without rediscovering the reasoning behind them.

Integration choices should follow your architecture. Use headless primitives when teams need portability and control over presentation. Use styled wrappers when consistency and rapid assembly matter more than visual freedom. Add framework bindings when they improve the consuming team’s workflow without duplicating the underlying interaction model.

Governance keeps those choices useful after the first release. Assign ownership, record component status, review contributions against a user need, document accessibility limitations, and give consumers a safe route through deprecations. Treat the library as a maintained product, not a folder of front-end utilities.

Start with this practical checklist:

  1. Inventory existing components. Find duplicate buttons, fields, dialogs, and patterns, then identify where their APIs or states differ.
  2. Inspect the DOM. Confirm that each component uses the native semantic element or provides a justified accessible pattern.
  3. Map states. Test keyboard focus, disabled and invalid conditions, loading, expanded, selected, and error behaviour where relevant.
  4. Separate primitives from patterns. Keep focused interaction logic small, then compose it into product-specific experiences.
  5. Choose one integration pilot. Try a headless primitive or a thin Vue wrapper in a contained workflow before changing the whole product.
  6. Write governance rules. Decide who reviews changes, how releases are communicated, and how consumers migrate away from deprecated APIs.

You don’t need to rebuild the entire system at once. Audit one high-use component, fix its accessibility and documentation gaps, and use what you learn to establish the next component’s standard.


DOM Studio provides accessible headless web component primitives alongside a thin Vue integration layer, including reactive props, v-model support, slots, and Tailwind CSS 4 styling. Visit DOM Studio to inspect its component patterns and use them as a practical reference while you build or scale your own library.