# How to Create Component Variants (Hover and Active States) in DESIGN.md

> Learn to create component variants like hover and active states in DESIGN.md. Master state-specific CSS by following simple naming conventions for dynamic components.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-06-28

---

**To create component variants in DESIGN.md, define a base component and add state-specific variants using the naming pattern `<component-name>-<state-suffix>`, such as `button-primary-hover` or `card-active`, which the parser automatically merges with the base definition.**

The [`google-labs-code/design.md`](https://github.com/google-labs-code/design.md/blob/main/google-labs-code/design.md) repository defines a design system specification that uses plain-text markdown with optional YAML frontmatter for design tokens and component definitions. Creating component variants for interactive states like hover and active follows a specific naming convention that allows the CLI linter to detect and resolve state-specific styling without duplicating entire component definitions.

## Understanding the Variant Naming Convention

DESIGN.md recognizes variants through a strict key-naming pattern. When the parser encounters a component key matching `<component-name>-<state-suffix>`, it treats this as a variant of the base component.

According to the specification in [`docs/spec.md`](https://github.com/google-labs-code/design.md/blob/main/docs/spec.md) (line 305), valid variant names follow this pattern:

- `button-primary` (base component)
- `button-primary-hover` (hover state)
- `button-primary-active` (active/pressed state)

The parser implementation in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts) detects these variant keys and merges their token values with the base component definition. This merging happens at the data structure level defined in [`packages/cli/src/linter/model/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/spec.ts), ensuring that variants inherit all base properties while overriding only specific values.

## Defining Hover and Active States

Variant definitions only need to specify properties that differ from the base component. This prevents duplication and keeps the design system maintainable.

### Basic Component with Hover Variant

Define the base component with full styling, then create a variant entry that overrides specific properties for the hover state:

```yaml
---
components:
  button-primary:
    background: "{colors.primary}"
    border: "2px solid {colors.primary}"
    color: "{colors.on-primary}"
    padding: "12px 24px"
    rounded: "{rounded.md}"
  button-primary-hover:
    background: "{colors.primary-variant}"
    border: "2px solid {colors.primary-variant}"
    color: "{colors.on-primary}"
---

```

The `button-primary-hover` variant inherits the `padding` and `rounded` values from `button-primary` while specifically overriding background and border colors for the hover interaction.

### Multiple State Variants

You can define several states for a single component by appending different suffixes:

```yaml
---
components:
  card:
    background: "{colors.surface}"
    border: "1px solid {colors.outline}"
    padding: "{spacing.md}"
    rounded: "{rounded.lg}"
  card-hover:
    background: "{colors.surface-variant}"
  card-active:
    background: "{colors.surface-active}"
---

```

This approach creates three distinct states—default, hover, and active—while minimizing repetition. The `card-hover` and `card-active` variants each change only the background property, inheriting border, padding, and radius from the base `card` definition.

## Referencing Design Tokens in Variants

Variants can reference design tokens using the `{token.path}` syntax, enabling consistent color palettes and spacing across all component states. The parser resolves these references at build time, allowing variants to use semantic color names like `{colors.primary-variant}` instead of hardcoded values.

When defining hover states, reference lighter or darker color variants from your token palette:

```yaml
components:
  button-primary-hover:
    background: "{colors.primary-variant}"  # Lighter shade for hover

```

This ensures that state changes remain consistent with your overall design system theme.

## Real-World Examples from the Repository

The [`examples/totality-festival/DESIGN.md`](https://github.com/google-labs-code/design.md/blob/main/examples/totality-festival/DESIGN.md) file demonstrates practical variant usage for badge components:

```yaml
---
components:
  badge:
    background: "{colors.secondary}"
    color: "{colors.on-secondary}"
  badge-info:
    background: "{colors.info}"
    color: "{colors.on-info}"
  badge-success:
    background: "{colors.success}"
    color: "{colors.on-success}"
---

```

Each variant (`badge-info`, `badge-success`) follows the naming convention and overrides only the colors that differ from the base `badge` component. The [`examples/paws-and-paths/DESIGN.md`](https://github.com/google-labs-code/design.md/blob/main/examples/paws-and-paths/DESIGN.md) file provides additional illustrations of variant token usage for interactive elements.

## Summary

- **Use the naming pattern** `<component-name>-<state-suffix>` (e.g., `button-primary-hover`) to define variants for hover, active, and other states.
- **Define only differing properties** in variant entries; the parser merges them with the base component automatically.
- **Reference design tokens** using `{token.path}` syntax to maintain consistency across states.
- **Locate the core logic** in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts) and [`packages/cli/src/linter/model/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/spec.ts).
- **Consult the specification** in [`docs/spec.md`](https://github.com/google-labs-code/design.md/blob/main/docs/spec.md) (line 305) for the official variant definition.

## Frequently Asked Questions

### What is the exact naming pattern for component variants in DESIGN.md?

Variants must follow the pattern `<component-name>-<state-suffix>`, where the suffix describes the UI state such as `hover`, `active`, or `pressed`. For example, `button-primary-hover` is recognized as a hover variant of the `button-primary` component. The parser in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts) identifies these keys by detecting the hyphen-separated suffix.

### How does the DESIGN.md parser handle variant inheritance?

The parser treats variant entries as partial definitions that extend their base components. When processing `button-primary-hover`, the system starts with all properties defined in `button-primary`, then applies any overrides specified in the variant entry. This merging occurs at the data structure level in [`packages/cli/src/linter/model/spec.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/spec.ts), ensuring variants inherit base values without requiring explicit duplication.

### Can variants reference other tokens or only literal values?

Variants can reference design tokens using the `{category.name}` syntax (e.g., `{colors.primary-variant}`). The parser resolves these references during the build process, allowing variants to use semantic tokens from your design system rather than hardcoded color values or measurements. This supports dynamic theming and ensures consistency across hover, active, and default states.

### Where is the variant specification documented in the source code?

The official variant specification resides in [`docs/spec.md`](https://github.com/google-labs-code/design.md/blob/main/docs/spec.md) at line 305, which states: "A component may have a variant for different UI states such as active, hover, pressed, etc." The implementation logic that enforces this specification lives in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts), which handles the detection and merging of variant keys during the linting process.