🔊 Sensory Processing Principles

Sensory processing differences are common in autism, ADHD, and other conditions. Users may be hypersensitive or hyposensitive to sensory input. Design should accommodate these differences and prevent sensory overload.

Design Guidelines

Principle Description Recommendation
Prevent Sensory Overload Reduce simultaneous stimuli Limit visual, auditory, and motion elements
Volume Control User-adjustable audio Provide volume controls, default to muted
No Autoplay User-initiated media Don't auto-play audio or video
Safe Patterns Avoid triggering textures No high-contrast repetitive patterns
Theme Control Environment customization Offer light/dark mode and custom themes
Dual Notification Multiple alert channels Provide both visual and auditory options

CSS Implementation

/* Avoid high-contrast repetitive patterns */
.safe-pattern {
  background-color: #f5f5f5;
  /* Avoid high-contrast stripes or checkered patterns */
}

/* Dark mode support */
@media (prefers-color-scheme: dark) {
  .safe-pattern {
    background-color: #1f2937;
  }
}

/* Reduced visual noise */
.reduced-noise {
  background: solid-color;
  border: none;
  box-shadow: none;
}

/* Soft, non-jarring colors */
.sensory-friendly {
  --bg-primary: #faf8f5;
  --text-primary: #1a1a1a;
  --accent: #4a7c59;
}

React Components

type Theme = "light" | "dark" | "system";

export function ThemeToggle() {
  const [theme, setTheme] = useState<Theme>("system");

  useEffect(() => {
    const root = document.documentElement;

    if (theme === "system") {
      const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
        .matches
        ? "dark"
        : "light";
      root.setAttribute("data-theme", systemTheme);
    } else {
      root.setAttribute("data-theme", theme);
    }
  }, [theme]);

  return (
    <div className="flex items-center gap-2">
      <button
        onClick={() => setTheme("light")}
        className={`btn btn-ghost btn-sm btn-circle ${theme === "light" ? "btn-active" : ""}`}
        aria-label="Light mode"
        aria-pressed={theme === "light"}
      >
        <Sun className="w-5 h-5" />
      </button>
      <button
        onClick={() => setTheme("dark")}
        className={`btn btn-ghost btn-sm btn-circle ${theme === "dark" ? "btn-active" : ""}`}
        aria-label="Dark mode"
        aria-pressed={theme === "dark"}
      >
        <Moon className="w-5 h-5" />
      </button>
      <button
        onClick={() => setTheme("system")}
        className={`btn btn-ghost btn-sm btn-circle ${theme === "system" ? "btn-active" : ""}`}
        aria-label="System preference"
        aria-pressed={theme === "system"}
      >
        <Monitor className="w-5 h-5" />
      </button>
    </div>
  );
}

// Audio/Video player with controls
interface MediaPlayerProps {
  src: string;
  type: "audio" | "video";
}

export function MediaPlayer({ src, type }: MediaPlayerProps) {
  return (
    <div className="relative">
      {type === "video" ? (
        <video
          src={src}
          controls
          className="w-full rounded-lg"
          // Don't autoplay
          autoPlay={false}
          // Default to muted
          muted
        />
      ) : (
        <audio src={src} controls className="w-full" autoPlay={false} />
      )}
    </div>
  );
}

Notification Component

interface NotificationSettings {
  visual: boolean;
  sound: boolean;
}

export function NotificationPreferences() {
  const [settings, setSettings] = useState<NotificationSettings>({
    visual: true,
    sound: false,
  });

  return (
    <div className="space-y-4">
      <h3 className="font-semibold">Notification Preferences</h3>

      <label className="flex items-center gap-3 cursor-pointer">
        <input
          type="checkbox"
          checked={settings.visual}
          onChange={(e) =>
            setSettings({ ...settings, visual: e.target.checked })
          }
          className="checkbox"
        />
        <Bell className="w-5 h-5" />
        Visual notifications
      </label>

      <label className="flex items-center gap-3 cursor-pointer">
        <input
          type="checkbox"
          checked={settings.sound}
          onChange={(e) =>
            setSettings({ ...settings, sound: e.target.checked })
          }
          className="checkbox"
        />
        <Volume2 className="w-5 h-5" />
        Sound notifications
      </label>
    </div>
  );
}

Checklist

  • No simultaneous overwhelming stimuli
  • Audio/video has volume controls
  • Media doesn't autoplay
  • No high-contrast repetitive patterns
  • Light/dark mode available
  • Custom theme options provided
  • Both visual and auditory notifications available
  • Background colors are soft and non-distracting

Last updated: 2026-10-20

Menu
Loading