# How to Implement Reduced Motion Support in Hallmark: A Complete Guide

> Learn how to implement reduced motion support in Hallmark. This guide shows you how to detect user preferences and disable animations globally for accessibility.

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

---

**Hallmark respects the `prefers-reduced-motion` media query by detecting the user preference once at load time and guarding all animations with a global boolean flag.**

The Hallmark repository by Nutlope provides a reference implementation for accessibility-first motion design. By centralizing the reduced motion check in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js), the project ensures that every interactive component—from theme transitions to hero animations—respects user accessibility preferences.

## Detecting the prefers-reduced-motion Preference

Hallmark detects the user's motion preference immediately upon initialization. In [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js), the code creates a global constant that evaluates the media query:

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

```

This single detection point (lines 5–6) stores the result in a boolean variable named `reduced`. All subsequent animation logic throughout the codebase references this flag, ensuring consistent behavior without repeated media query evaluations.

## Guarding Core Animations in main.js

The primary implementation guards motion-heavy operations using early returns or conditional blocks. When swapping themes, Hallmark conditionally uses the View Transitions API only when motion is not reduced:

```javascript
if (!reduced && document.startViewTransition) {
  document.startViewTransition(apply);
}

```

This pattern appears at lines 761–762 in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js). The code checks both the `reduced` flag and API availability before invoking the transition. If the user prefers reduced motion, the theme applies instantly without the morphing animation.

## Implementing Reduced Motion in Example Demos

Individual examples in the Hallmark repository follow the same detection and guarding pattern, demonstrating how to apply the pattern across different animation contexts.

### Tally Demo Animation Guard

In [`site/examples/tally/app.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/tally/app.js), the demo reads the media query into a specifically named boolean:

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

// Later in animation logic
if (reduceMotion) {
  // Skip motion-heavy transitions
  return;
}

```

### Riso Demo Hero Animation

The [`site/examples/riso-01/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/riso-01/script.js) file creates a `reduced` flag and conditionally runs the hero entrance animation:

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

function animateHero() {
  if (reduced) return;
  // Perform entrance animation logic
}

```

### Custom-05 Scroll Behaviors

In [`site/examples/custom-05/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/custom-05/script.js), the implementation adds explicit comments explaining that when reduced motion is preferred, the component disables the "traveling playhead" and scroll-linked animations. This documents the accessibility rationale directly in the source code.

## Best Practices for Adding New Components

When extending Hallmark with new interactive elements, follow the established four-step pattern:

1. **Detect** the preference once at load time using `matchMedia("(prefers-reduced-motion: reduce)")`
2. **Store** the result in a descriptive boolean (`reduced` or `reduceMotion`)
3. **Guard** all animation entry points with `if (!reduced) { ... }` or early return statements
4. **Avoid** CSS-only animations that cannot be toggled via JavaScript; Hallmark already marks `.reveal` elements as visible on page load to prevent scroll-triggered motion

## Summary

- **Centralize detection** by creating a global `reduced` flag in your main entry file using `matchMedia`
- **Guard view transitions** by checking `!reduced && document.startViewTransition` before calling the API
- **Follow existing patterns** in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) and example demos like [`tally/app.js`](https://github.com/Nutlope/hallmark/blob/main/tally/app.js) for consistent implementation
- **Document accessibility choices** with comments explaining why specific animations are disabled
- **Provide instant fallbacks** that execute immediately when motion is reduced, ensuring functionality remains accessible

## Frequently Asked Questions

### How does Hallmark detect reduced motion preferences?

Hallmark uses `window.matchMedia("(prefers-reduced-motion: reduce)").matches` at application startup to create a boolean flag. This detection occurs in [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) and stores the result in a `const reduced` variable that the entire application references.

### What happens to theme transitions when reduced motion is enabled?

When `reduced` is true, Hallmark skips the `document.startViewTransition` API call and executes the theme change logic immediately. This prevents the morphing visual effect while maintaining instant functional feedback for the user.

### Can I use CSS animations instead of JavaScript guards?

Hallmark specifically avoids CSS-only animation triggers for motion-sensitive elements. The repository explicitly marks elements with the `.reveal` class as already visible on page load to prevent scroll-based CSS animations from running, ensuring JavaScript maintains full control over motion rendering.

### Which files should I reference when implementing reduced motion in my own Hallmark components?

Reference [`site/js/main.js`](https://github.com/Nutlope/hallmark/blob/main/site/js/main.js) for the global flag pattern and theme transition logic, [`site/examples/tally/app.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/tally/app.js) for per-component motion detection, and [`site/examples/riso-01/script.js`](https://github.com/Nutlope/hallmark/blob/main/site/examples/riso-01/script.js) for animation entry point guarding. These files demonstrate the complete implementation spectrum from global to local scope.