storybook: Can't access styled-components theme in stories

Describe the bug I’m using styled-components in combination with @storybook/react. I’m wrapping all my stories in the SC ThemeProvider like this:

addDecorator((storyFn) => (
    <ThemeProvider theme={themeBasic}>
        {storyFn()}
    </ThemeProvider>
));

This works fine and all of my Styled Components have access to the theme. However, I also want to access the theme in my stories:

import { ThemeContext } from 'styled-components';

export const Configurable = () => {
    const theme = useContext(ThemeContext);
    console.log(theme); // undefined

    return (
        // Some React stuff here
    );
};

Shouldn’t this be working?

System:

Environment Info:

  System:
    OS: macOS 10.15
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
  Binaries:
    Node: 10.16.0 - /usr/local/bin/node
    Yarn: 1.17.3 - /usr/local/bin/yarn
    npm: 6.12.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 78.0.3904.70
    Firefox: 69.0.3
    Safari: 13.0.2
  npmPackages:
    @storybook/addon-actions: ^5.2.5 => 5.2.5
    @storybook/addon-backgrounds: ^5.2.5 => 5.2.5
    @storybook/addon-info: ^5.2.5 => 5.2.5
    @storybook/addon-knobs: ^5.2.5 => 5.2.5
    @storybook/react: ^5.2.5 => 5.2.5

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 27 (6 by maintainers)

Most upvoted comments

I guess this issue is the same as https://github.com/storybookjs/storybook/issues/8426. If so, this could solve your problem. (NOTE: I didn’t test the code. Just saw the workaround.)

// Using StoryFn as component instead of invoking it
addDecorator(StoryFn => (
    <ThemeProvider theme={themeBasic}>
        <StoryFn/>
    </ThemeProvider>
));

According to the latest docs (v5.3), you need to add a global decorator in .storybook/preview.js:

import React from "react";
import { addDecorator } from '@storybook/react';
import { ThemeProvider } from "styled-components";
import theme from "../src/theme";

addDecorator(storyFn => <ThemeProvider theme={theme}>{storyFn()}</ThemeProvider>)

https://storybook.js.org/docs/addons/introduction/#storybook-decorators

storybook 6 version(preview.js)

import { ThemeProvider } from "styled-components";
import { Defaultheme } from "../src/components/themes"; 
const themeDecorator = storyFn => <ThemeProvider theme={Defaultheme}>{storyFn()}</ThemeProvider>
export const decorators = [themeDecorator];

@PatFawbertMills you add it to .storybook/preview.js.

In 5.3:

import { addDecorator } from '@storybook/react';
addDecorator(myDecorator)

In 6.0:

export const decorators = [myDecorator];

Hi @daviddelusenet 👋 – please see this example:

https://github.com/kylesuss/styled-components-storybook-theme-example/blob/89f2193bb87f208a351b47b107c0eba1beb96b49/src/index.stories.js

You can do what you need to do, but you need another component to do it – you can’t just put the useContext stuff in the component story function. Why? Not sure exactly to be honest. Maybe somebody with a bit more knowledge on that can chime in here.

In version 6 I managed to do this by adding the theme to the args property that is passed to all components :

import theme from './../theme.tsx';
const withThemeProvider = (Story, context) => {
  // Pass the theme to all story args.
  context.args = { ...context.args, ...{ theme } };
  return (
    <ThemeProvider theme={theme}>
      <>
        <div>
          <GlobalStyle />
          <AppGlobalStyle />
          <Story {...context} />
        </div>
      </>
    </ThemeProvider>
  );
};
export const decorators = [withThemeProvider];

This way in a story I can grab the theme like this :

export const NavbarBox = ({ theme }) => {
  return (
    <Navbar>
      <img src={theme.logo} alt="Logo" title="Logo" />
      <div>
        <MenuLink>Home</MenuLink>
        <MenuLink>My account</MenuLink>
        <MenuLink>Settings</MenuLink>
        <MenuLink>Logout</MenuLink>
      </div>
    </Navbar>
  );
};
NavbarBox.story = {
  title: 'Header'
};

Main use case for me is that I am using the same storybook and shipping to many clients and some of the branding I want to have in the stories (e.g. logo in this story should adapt to whatever logo set in the theme object

I guess this issue is the same as #8426. If so, this could solve your problem. (NOTE: I didn’t test the code. Just saw the workaround.)

// Using StoryFn as component instead of invoking it
addDecorator(StoryFn => (
    <ThemeProvider theme={themeBasic}>
        <StoryFn/>
    </ThemeProvider>
));

This worked for me! Thank you so much, it was driving me crazy!

Feel free to give a try to an addon I’ve built. It supports also changing the background-color of the storybook (to simulate a real theming experience)

https://github.com/semoal/themeprovider-storybook