Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      May 19, 2025

      Sunshine And March Vibes (2025 Wallpapers Edition)

      May 19, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      May 19, 2025

      How To Prevent WordPress SQL Injection Attacks

      May 19, 2025

      My latest hands-on could be the best value AI laptop of the summer, but I still have questions

      May 19, 2025

      DOOM: The Dark Ages had the lowest Steam launch numbers in series history — Is it suffering from the ‘Game Pass Effect’?

      May 19, 2025

      Microsoft won’t be left exposed if something “catastrophic” happens to OpenAI — but may still be 3 to 6 months behind ChatGPT

      May 19, 2025

      Microsoft Copilot gets OpenAI’s GPT-4o image generation support — but maybe a day late and a dollar short for the hype?

      May 19, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      ES6: Set Vs Array- What and When?

      May 19, 2025
      Recent

      ES6: Set Vs Array- What and When?

      May 19, 2025

      Transform JSON into Typed Collections with Laravel’s AsCollection::of()

      May 19, 2025

      Deployer

      May 19, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      My latest hands-on could be the best value AI laptop of the summer, but I still have questions

      May 19, 2025
      Recent

      My latest hands-on could be the best value AI laptop of the summer, but I still have questions

      May 19, 2025

      DOOM: The Dark Ages had the lowest Steam launch numbers in series history — Is it suffering from the ‘Game Pass Effect’?

      May 19, 2025

      Microsoft won’t be left exposed if something “catastrophic” happens to OpenAI — but may still be 3 to 6 months behind ChatGPT

      May 19, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to make Storybook Interactions respect user motion preferences

    How to make Storybook Interactions respect user motion preferences

    November 20, 2024

    Recently, while browsing my company’s Storybook, I came across something that seemed broken: a flickering component that appeared to be re-rendering repeatedly. The open source tool that helps designers, developers, and others build and use reusable components was behaving weirdly. As I dug in, I realized I was seeing the unintended effects of the Storybook Interactions addon, which allows developers to simulate user interactions within a story, in action.

    Storybook Interactions can be a powerful tool, enabling developers to simulate and test user behaviors quickly. But if you’re unfamiliar with Interactions—especially if you’re just looking to explore available components—the simulated tests jumping around on the screen can feel disorienting.

    This can be especially jarring for users who have the prefers-reduced-motion setting enabled in their operating system. When these users encounter a story that includes an interaction, their preferences are ignored and they have no option to disable or enable it. Instead, the Storybook Interaction immediately plays on page load, regardless. These rapid screen movements can cause disorientation for users or in some cases can even trigger a seizure.

    Knowledge share

    Operating systems allow users to set a motion preference. Adhering to this setting can be critical for some users. For example, for users who have photosensitive epilepsy or vertigo, even a small animation can be life-threatening.

    This explicit preference for a reduced motion experience can be used by browsers, applications, and websites to reduce unnecessary animations and motions via the prefers-reduced-motion CSS media feature.

    At this time, Storybook does not have built-in capabilities to toggle interactions on or off. Until this feature can be baked in I am hoping this blog will provide you with an alternative way to make your work environment more inclusive. Now, let’s get into building an addon that respects user’s motion preferences and allows users to toggle interactions on and off.

    Goals

    1. Users with prefers-reduced-motion enabled MUST have interactions off by default.
    2. Users with prefers-reduced-motion enabled MUST have a way to toggle the feature on or off without altering their operating system user preferences.
    3. All users SHOULD have a way to toggle the feature on or off without altering their user preferences.

    Let’s get started

    Step 1: Build a Storybook addon

    Storybook allows developers to create custom addons. In this case, we will create one that will allow users to toggle Interactions on or off, while respecting the prefers-reduced-motion setting.

    Add the following code to a file in your project’s .storybook folder:

    import React, {useCallback, useEffect} from 'react'
    
    import {IconButton} from '@storybook/components'
    import {PlayIcon, StopIcon} from '@storybook/icons'
    
    export const ADDON_ID = 'toggle-interaction'
    export const TOOL_ID = `${ADDON_ID}/tool`
    
    export const INTERACTION_STORAGE_KEY = 'disableInteractions'
    
    export const InteractionToggle = () => {
      const [disableInteractions, setDisableInteractions] = React.useState(
           window?.localStorage.getItem(INTERACTION_STORAGE_KEY) === 'true',
      )
    
      useEffect(() => {
        const reducedMotion = matchMedia('(prefers-reduced-motion)')
    
        if (window?.localStorage.getItem(INTERACTION_STORAGE_KEY) === null && reducedMotion.matches) {
          window?.localStorage?.setItem(INTERACTION_STORAGE_KEY, 'true')
          setDisableInteractions(true)
        }
      }, [])
    
      const toggleMyTool = useCallback(() => {
        window?.localStorage?.setItem(INTERACTION_STORAGE_KEY, `${!disableInteractions}`)
        setDisableInteractions(!disableInteractions)
          // Refreshes the page to cause the interaction to stop/start
          window.location.reload()
    }, [disableInteractions, setDisableInteractions])
    
      return (
        <IconButton
          key={TOOL_ID}
          aria-label="Disable Interactions"
          onClick={toggleMyTool}
          defaultChecked={disableInteractions}
          aria-pressed={disableInteractions}
        >
          {disableInteractions ? <PlayIcon /> : <StopIcon />}
          Interactions
        </IconButton>
      )
    }
    

    Code breakdown

    This addon stores user preferences for Interactions using window.localStorage. When the addon first loads, it checks whether the preference is already set and, if so, it defaults to the user’s preference.

    const [disableInteractions, setDisableInteractions] = React.useState(
           window?.localStorage.getItem(INTERACTION_STORAGE_KEY) === 'true',
      )
    

    This useEffect hook checks if a user has their motion preferences set to prefers-reduced-motion and ensures that Interactions are turned off if the user hasn’t already set a preference in Storybook.

    useEffect(() => {
        const reducedMotion = matchMedia('(prefers-reduced-motion)')
    
        if (window?.localStorage.getItem(INTERACTION_STORAGE_KEY) === null && reducedMotion.matches) {
          window?.localStorage?.setItem(INTERACTION_STORAGE_KEY, 'true')
          setDisableInteractions(true)
        }
      }, [])
    

    When a user clicks the toggle button, preferences are updated and the page is refreshed to reflect the changes.

    const toggleMyTool = useCallback(() => {
        window?.localStorage?.setItem(INTERACTION_STORAGE_KEY, `${!disableInteractions}`)
        setDisableInteractions(!disableInteractions)
          // Refreshes the page to cause the interaction to stop/start
          window.location.reload()
      }, [disableInteractions, setDisableInteractions])
    

    Step 2: Register your new addon with Storybook

    In your .storybook/manager file, register your new addon:

    addons.register(ADDON_ID, () => {
      addons.add(TOOL_ID, {
        title: 'toggle interaction',
        type: types.TOOL as any,
        match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,
        render: () => <InteractionToggle />,
      })
    })
    

    This adds the toggle button to the Storybook toolbar, which will allow users to change their Storybook Interaction preferences.

    Step 3: Add functionality to check user preferences

    Finally, create a function that checks whether Interactions should be played and add it to your interaction stories:

    import {INTERACTION_STORAGE_KEY} from './.storybook/src/InteractionToggle'
    
    export const shouldInteractionPlay = () => {
      const disableInteractions = window?.localStorage?.getItem(INTERACTION_STORAGE_KEY)
      return disableInteractions === 'false' || disableInteractions === null
    }
    
    
     export const SomeComponentStory = {
      render: SomeComponent,
      play: async ({context}) => {
        if (shouldInteractionPlay()) {
    ...
        }
      })
     }
    

    Wrap-up

    With this custom addon, you can ensure your workplace remains accessible to users with motion sensitivities while benefiting from Storybook’s Interactions. For those with prefers-reduced-motion enabled, motion will be turned off by default and all users will be able to toggle interactions on or off.

    The post How to make Storybook Interactions respect user motion preferences appeared first on The GitHub Blog.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleInvoker Commands: Additional Ways to Work With Dialog, Popover… and More?
    Next Article Internal vs External Penetration Testing: Key Differences

    Related Posts

    Security

    Nmap 7.96 Launches with Lightning-Fast DNS and 612 Scripts

    May 19, 2025
    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-48259 – Juan Carlos WP Mapa Politico España CSRF

    May 19, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    Wi-Fi 8: Stability, not speed, is the name of its game

    Development

    Faceless YouTube Channels Using AutoShorts AI: The Future of High-Earnings Unlocked!

    Artificial Intelligence

    Woman scammed out of €800k by an AI deep fake of Brad Pitt

    Artificial Intelligence

    Generative AI in Marketing and Sales: A Comprehensive Review

    Development

    Highlights

    Machine Learning

    This AI Paper Introduces PLAN-AND-ACT: A Modular Framework for Long-Horizon Planning in Web-Based Language Agents

    March 26, 2025

    Large language models are powering a new wave of digital agents to handle sophisticated web-based…

    Build Verification Testing (BVT Testing) – A Quick Guide to Ensure Quality Software Releases

    July 9, 2024

    SAP fixes suspected Netweaver zero-day exploited in attacks

    April 25, 2025

    I was wrong about databases

    February 13, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.