# 8 Required States for Hallmark Interactive Components: The Complete Implementation Guide

> Implement the 8 required Hallmark interactive component states Default Hover Focus-Visible Active Disabled Error Loading and Filled Success for consistent accessible UIs. Learn how.

- Repository: [Hassan El Mghari/hallmark](https://github.com/Nutlope/hallmark)
- Tags: how-to-guide
- Published: 2026-07-21

---

**Hallmark mandates that every interactive element implement eight specific UI states—Default, Hover, Focus-Visible, Active, Disabled, Error, Loading, and Filled/Success—to ensure consistent, accessible, and predictable user interfaces.**

The Hallmark design system, maintained in the `Nutlope/hallmark` repository, enforces rigorous interaction standards to prevent "almost-right" UI failures. According to [`skills/hallmark/references/interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/interaction-and-states.md), **every interactive component must implement eight required states** to meet the system's accessibility and consistency baseline. Missing any state—particularly `:focus-visible`, `:active`, or `:disabled`—is considered a failure mode that results in broken user experiences.

## The Eight Required States Explained

The [`interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/interaction-and-states.md) reference file enumerates eight mandatory conditions that every button, input, link, or card must support:

| State | Purpose | Critical Requirement |
|-------|---------|---------------------|
| **Default** | Baseline appearance when no interaction occurs | Serves as the visual foundation |
| **Hover** | Pointer feedback via subtle background or elevation shifts | Must not rely on color alone |
| **Focus-Visible** | Keyboard-focus indicator for accessibility | Requires visible focus ring or outline |
| **Active / Pressed** | Immediate feedback during press events | Often rendered as inset shadows or scale transforms |
| **Disabled** | Non-interactive visual indication | Must remove pointer events and maintain layout stability |
| **Error** | Validation or runtime failure state | Requires red borders, error icons, and `aria-invalid` attributes |
| **Loading** | Async operation in progress | Display inline spinners or reduced opacity while preserving dimensions |
| **Filled / Success** | Completed or valid state | Checkmarks, accent colors, or stronger borders indicating success |

## Why the Eight-State Rule Matters

Adhering to all eight states prevents common UI defects that plague AI-generated interfaces. The [`microinteractions.md`](https://github.com/Nutlope/hallmark/blob/main/microinteractions.md) file emphasizes that **border-width must remain constant across states** to avoid layout shifts, while the [`component-cookbook.md`](https://github.com/Nutlope/hallmark/blob/main/component-cookbook.md) demonstrates how `:focus-visible` guarantees keyboard navigability.

These states provide:
- **Accessibility**: `:focus-visible` ensures keyboard users can locate elements
- **Consistency**: Uniform state handling prevents jarring layout changes
- **Feedback**: `:active` and loading states confirm that actions are received
- **Error Clarity**: Dedicated error states eliminate ambiguous color-only signals

## Implementing the Eight States in Code

The following patterns from [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) and the component cookbook demonstrate semantic implementation using `data-state` attributes.

### Base HTML Structure

Start with a neutral element that accepts state attributes:

```html
<button class="btn" data-state="">
  <span class="btn__label">Submit</span>
</button>

```

### CSS State Definitions

Define all eight states using CSS custom properties to maintain visual consistency:

```css
/* ---- Base (Default) ---- */
.btn {
  --bg: var(--color-surface);
  --fg: var(--color-on-surface);
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--color-rule-2);
  border-radius: 0.5rem;
  transition: background 150ms ease, box-shadow 150ms ease;
}

/* ---- Hover ---- */
.btn:hover {
  background: var(--color-surface-hover);
}

/* ---- Focus-Visible ---- */
.btn:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* ---- Active / Pressed ---- */
.btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 0 0 1px var(--color-shadow);
}

/* ---- Disabled ---- */
.btn:disabled,
.btn[data-state="disabled"] {
  opacity: 0.5;
  pointer-events: none;
}

/* ---- Error ---- */
.btn[data-state="error"] {
  border-color: var(--color-error);
  background: var(--color-error-bg);
}

/* ---- Loading ---- */
.btn[data-state="loading"] .btn__label {
  visibility: hidden;
}
.btn[data-state="loading"]::after {
  content: "";
  display: inline-block;
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--color-on-surface);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* ---- Filled / Success ---- */
.btn[data-state="filled"] {
  background: var(--color-success);
  border-color: var(--color-success);
}

```

### JavaScript State Management

Toggle states programmatically while handling async operations:

```javascript
const btn = document.querySelector('.btn');

btn.addEventListener('click', async () => {
  // Switch to loading state
  btn.dataset.state = 'loading';
  
  try {
    await doSomethingAsync();
    btn.dataset.state = 'filled';  // Success state
  } catch (e) {
    btn.dataset.state = 'error';
  } finally {
    // Reset after delay
    setTimeout(() => btn.dataset.state = '', 2000);
  }
});

```

## Key Reference Files

The eight-state requirement is documented across several files in the Hallmark repository:

- [`skills/hallmark/references/interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/interaction-and-states.md) — Central reference listing the eight required states and compliance checklists
- [`skills/hallmark/references/microinteractions.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/microinteractions.md) — Timing, easing functions, and reduced-motion handling for state transitions
- [`skills/hallmark/references/component-cookbook.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/component-cookbook.md) — Example implementations demonstrating the eight-state rule
- [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) — Runtime logic toggling `data-state` attributes throughout the demo site

## Summary

- Hallmark requires **eight specific states** for every interactive component: Default, Hover, Focus-Visible, Active, Disabled, Error, Loading, and Filled/Success
- Implementation uses semantic `data-state` attributes and consistent CSS custom properties
- The [`interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/interaction-and-states.md) file serves as the canonical reference for these requirements
- Missing states—especially `focus-visible` or `disabled`—constitutes a system failure
- State transitions must preserve layout dimensions to prevent reflow (stable border-widths)

## Frequently Asked Questions

### What happens if I skip one of the eight states in my component?

Skipping any state violates the Hallmark design system contract. According to the [`interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/interaction-and-states.md) documentation, omitting `:focus-visible` breaks keyboard accessibility, while missing `:disabled` states can confuse users about interactive availability. The system treats incomplete state handling as a "failure mode" that produces broken UI experiences.

### How does the focus-visible state differ from the standard focus state in Hallmark?

Hallmark specifically mandates `focus-visible` over standard `:focus` to ensure keyboard-only users receive clear indicators while mouse users avoid persistent focus rings. As implemented in the component cookbook, this state uses `outline: 2px solid var(--color-focus)` with a 2px offset, providing high-contrast visibility without relying on browser defaults that may be removed by reset styles.

### Where are the eight required states officially documented?

The canonical documentation resides in [`skills/hallmark/references/interaction-and-states.md`](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/interaction-and-states.md) within the `Nutlope/hallmark` repository. This file contains the definitive table enumerating all eight states, their visual cues, and accessibility requirements. Supplementary implementation details appear in [`microinteractions.md`](https://github.com/Nutlope/hallmark/blob/main/microinteractions.md) and [`component-cookbook.md`](https://github.com/Nutlope/hallmark/blob/main/component-cookbook.md).

### Can I customize the visual appearance of these states while maintaining compliance?

Yes, provided you preserve the functional semantics and accessibility requirements. The [`component-cookbook.md`](https://github.com/Nutlope/hallmark/blob/main/component-cookbook.md) demonstrates using CSS custom properties (`var(--color-surface)`, `var(--color-error)`) to theme states, but mandates that **border-widths remain constant** across transitions to prevent layout shifts. Custom animations are acceptable if they respect `prefers-reduced-motion` settings as detailed in [`microinteractions.md`](https://github.com/Nutlope/hallmark/blob/main/microinteractions.md).