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

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, 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 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 file emphasizes that border-width must remain constant across states to avoid layout shifts, while the 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 and the component cookbook demonstrate semantic implementation using data-state attributes.

Base HTML Structure

Start with a neutral element that accepts state attributes:

<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:

/* ---- 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:

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:

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 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 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 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 and 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →