# How Hallmark Handles Reduced-Motion Accessibility for Motion-Sensitive Users

> Discover how Hallmark ensures reduced-motion accessibility. Learn how it detects user preferences and disables animations for a smoother experience.

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

---

**Hallmark detects the `prefers-reduced-motion` media query on page load and conditionally disables all animated transitions, view transitions, and scroll-linked effects when users have requested reduced motion.**

Hallmark is an open-source accessibility toolkit by Nutlope that helps developers build motion-aware interfaces. As implemented in the Hallmark repository, reduced-motion support is built into the core architecture rather than added as an afterthought. The framework automatically respects user preferences at both the system level and within individual demo implementations.

---

## Detecting Reduced-Motion Preferences in Hallmark

The foundation of Hallmark's accessibility approach lives in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js). On initialization, the script creates a persistent Boolean flag that captures the user's motion preference:

```javascript
// Detect the reduced-motion preference once at startup.
const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;

```

This single detection at line 5 propagates throughout the entire application. By evaluating the `matchMedia` query immediately, Hallmark avoids repeated DOM queries and ensures consistent behavior across all subsequent motion checks.

---

## Guarding View-Transition Animations

Modern Chromium browsers support the **View Transitions API** for smooth state changes. Hallmark leverages this for theme switches but only when motion is not restricted.

In [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) at lines 761-762, the `applyTheme()` function checks the `reduced` flag before invoking `document.startViewTransition()`:

```javascript
function applyTheme(theme) {
  if (!THEMES[theme]) return;
  const apply = () => {
    root.dataset.theme = theme;
    swapArchetypes(theme);
    setPressed(theme);
  };
  // Only use View Transition if the user has NOT requested reduced motion.
  if (!reduced && document.startViewTransition) {
    document.startViewTransition(apply);
  } else {
    apply();
  }
}

```

When `reduced` is `true`, the theme change executes instantly through the `apply()` callback. Users experience immediate visual feedback without the sliding, fading, or morphing effects that could trigger vestibular disorders.

---

## Example-Level Reduced-Motion Implementation

Hallmark's demo examples demonstrate the same pattern independently. Each example script performs its own `matchMedia` query, ensuring self-contained accessibility even when copied or modified.

### Tally Demo ([`site/examples/tally/app.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/tally/app.js))

```javascript
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

```

The tally animation respects this flag at its source, skipping number-counting transitions when motion reduction is preferred.

### Hyperlane Demo ([`site/examples/hyperlane/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/hyperlane/script.js))

Line 14 guards the hero entrance animation:

```javascript
if (!reduced) {
  // Animate hero elements into view
}

```

Without this check, the parallax scrolling and entrance effects would play regardless of user settings.

### Cobalt Demo ([`site/examples/cobalt-01/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/cobalt-01/script.js))

This example takes the most comprehensive approach at line 6, bypassing its entire animation system when `reduceMotion` is detected:

```javascript
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduceMotion) {
  // Run animated sequence…
} else {
  // Fallback: static layout or instantly-shown content.
}

```

The pattern repeats across `press-01`, `garden-01`, `custom-02`, and other examples in the `site/examples/` directory.

---

## Key Implementation Files

Understanding where Hallmark implements reduced-motion accessibility helps you audit your own adaptations:

| File | Purpose |
|------|---------|
| [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) | Core detection and theme transition guarding |
| [`site/examples/tally/app.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/tally/app.js) | Interactive tally with motion-conditional counting |
| [`site/examples/hyperlane/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/hyperlane/script.js) | Hero animation with reduced-motion fallback |
| [`site/examples/cobalt-01/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/cobalt-01/script.js) | Complete animation bypass implementation |
| `site/examples/*/script.js` | Additional examples following the same pattern |

---

## Adapting Hallmark's Pattern in Your Projects

To implement Hallmark-style reduced-motion handling in your own code:

1. **Detect once at initialization** – Store `matchMedia("(prefers-reduced-motion: reduce)").matches` in a constant or state variable.
2. **Guard every animation entry point** – Check the flag before calling `document.startViewTransition()`, `requestAnimationFrame()` loops, or CSS animation triggers.
3. **Provide instantaneous fallbacks** – Ensure your `else` branches render final states immediately, not merely delayed states.
4. **Test with actual user preferences** – Enable "Reduce motion" in macOS System Settings > Accessibility or Windows Settings > Ease of Access.

This approach satisfies **WCAG 2.1 Success Criterion 2.3.3** (Animation from Interactions) without requiring users to hunt for site-specific motion toggles.

---

## Summary

- **Hallmark detects reduced-motion preferences immediately** via `matchMedia("(prefers-reduced-motion: reduce)")` in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js)
- **Theme transitions use View Transitions API only when motion is permitted**, falling back to instant application otherwise
- **Every demo example implements independent motion guarding**, making the pattern copy-paste friendly
- **No configuration required** – accessibility activates automatically based on user system preferences
- **Consistent file structure** makes Hallmark's accessibility approach auditable and teachable

---

## Frequently Asked Questions

### Does Hallmark require JavaScript for reduced-motion support?

Yes, Hallmark's reduced-motion detection depends on JavaScript's `window.matchMedia()` API. The framework assumes a progressive enhancement approach where base content remains accessible without scripts, but motion suppression specifically requires the detection script to run.

### Can I override Hallmark's reduced-motion detection?

The `reduced` constant in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) is hardcoded to the media query result. To override for testing or specific use cases, you would need to modify the source or wrap animation calls with your own conditional logic. The examples demonstrate how to add custom guards without touching core files.

### Does Hallmark reduce motion for CSS animations as well?

Hallmark's JavaScript detection primarily guards programmatic animations and View Transitions. For CSS-only animations, you should pair Hallmark's script with standard media queries: `@media (prefers-reduced-motion: reduce) { /* static styles */ }` in your stylesheets.

### Which browsers support Hallmark's reduced-motion features?

The core `matchMedia` detection works in all modern browsers. The `document.startViewTransition()` API used for theme changes requires Chromium 111+. In unsupported browsers, Hallmark's `else` branch ensures themes still apply instantly, maintaining accessibility across browser generations.