# styled-theming: a theme lookup for styled-components

> styled-theming is a small helper that adds a theme(name, values) function to styled-components, so a component can declare one CSS value per theme mode and let the theme provider pick the right one. The values can be strings, functions, or whole css blocks, and there is a second helper for component variants.

**styled-components/styled-theming** — Create themes for your app using styled-components

- Repository: https://github.com/styled-components/styled-theming
- Stars: 1,167 · Forks: 25
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/styled-components-styled-theming

## What the package actually adds

styled-theming is described as a way to create themes for your app using styled-components, and the README points to an introductory blog post for the longer explanation. It is a very small package, and the whole API is a default export that is a function with one extra method attached.

The installation is a normal dependency add:

```sh
yarn add styled-components styled-theming
```

The usage example shows the whole idea in a dozen lines. You import styled and ThemeProvider from styled-components, and the default export from styled-theming, then call theme('mode', { light: '#fff', dark: '#000' }) to get a value you can interpolate into a styled component:

```js
import React from 'react';
import styled, {ThemeProvider} from 'styled-components';
import theme from 'styled-theming';

const boxBackgroundColor = theme('mode', {
  light: '#fff',
  dark: '#000',
});

const Box = styled.div`
  background-color: ${boxBackgroundColor};
`;

export default function App() {
  return (
    <ThemeProvider theme={{ mode: 'light' }}>
      <Box>
        Hello World
      </Box>
    </ThemeProvider>
  );
}
```

The idea is that the component declares the values for every mode, and the theme provider decides which one applies. The alternative, which is what most teams end up with, is a single theme object with nested mode keys, where a component reads props.theme.colors.background. That works, but the values end up scattered across the theme object, and a component that only differs between light and dark still has to reach into a deeply nested structure.

The project is MIT licensed, the primary language is JavaScript, the default branch is master, and the last push to the repository was on 2026-06-10. The version is 2.2.0, there are no GitHub releases, and the author is James Kyle, whose name also appears in the blog post URL.

## The ThemeProvider contract, and the getter form

ThemeProvider is part of styled-components, but it is required for styled-theming, and the documentation is explicit about that. The prop it accepts is theme, and you should pass an object with either strings or getter functions.

```js
<ThemeProvider theme={{ mode: 'dark', size: 'large' }}>
<ThemeProvider theme={{ mode: modes => modes.dark, size: sizes => sizes.large }}>
```

The second form is the interesting one. Instead of passing a fixed value, you pass a function, and the framework calls it. That means the mode can be computed at render time rather than hardcoded, which is what you need when the theme depends on state, a user preference, or the operating system's colour scheme.

The guidance is to generally set up a ThemeProvider at the root of your app:

```js
function App() {
  return (
    <ThemeProvider theme={...}>
      {/* rest of your app */}
    </ThemeProvider>
  );
}
```

The name should match one of the keys in the ThemeProvider theme, so theme('whatever', {...}) pairs with a provider whose theme has a whatever key. The values object is where one of the keys is selected by the value provided to the provider, so with a provider of mode: 'light' the light entry is chosen.

The values can be any CSS value, and the documentation gives three examples that show the range: a colour, a font stack, and a value that is itself a function of the props.

```js
theme('mode', {
  light: props => props.theme.userProfileAccentColor.light,
  dark: props => props.theme.userProfileAccentColor.dark,
});
```

That last form is the one that makes the package compose with an existing theme object. The mode values are still declared locally, but they read from a shared palette, so you get the locality of a per-component declaration without losing a single source of truth for the colours.

## Values can be whole css blocks

The values are passed through like any other interpolation in styled-components, and the documentation notes that you can use the css helper to add entire blocks of styles, including their own interpolations.

```js
import styled, {css} from 'styled-components';
import theme from 'styled-theming';

const white = "#fff";
const black = "#000";

const boxStyles = theme('mode', {
  light: css`
    background: ${white};
    color: ${black};
  `,
  dark: css`
    background: ${black};
    color: ${white};
  `,
});

const Box = styled.div`
  ${boxStyles}
`;
```

This is the part that makes the helper more than a colour lookup. A CSS value is a single declaration, but a mode often changes a set of declarations together, and in this example a background and a foreground have to flip in opposite directions, which is exactly the case where a single interpolated value cannot express the relationship. Putting the pair in a css block lets the light and dark variants declare the relationship explicitly, and the two blocks are swapped as a unit.

So the shape of the API is: theme() returns something that behaves like a styled-components interpolation, and that something can be a plain value, a function of props, or a css block containing either. The package does not have to understand any of that, because styled-components already does.

## Variants, and the prop that selects them

The second export is theme.variants, and it exists for a common component pattern.

The reasoning is that it is often useful to create variants of the same component that are selected via an additional prop, and to make this easier with theming, styled-theming provides a theme.variants function.

```js
import styled from 'styled-components';
import theme from 'styled-theming';

const backgroundColor = theme.variants('mode', 'variant', {
  default: { light: 'gray', dark: 'darkgray' },
  primary: { light: 'blue', dark: 'darkblue' },
  success: { light: 'green', dark: 'darkgreen' },
  warning: { light: 'orange', dark: 'darkorange' },
});

const Button = styled.button`
  background-color: ${backgroundColor};
`;
```

There are three axes to read there. The first argument is the name of the theme key, mode, which selects between light and dark. The second is the name of the prop that selects the variant, variant, and the third is the set of variants, where each variant maps a mode to a value.

So the lookup is two-dimensional: the mode comes from the theme provider and the variant comes from a prop on the component, and the value is whichever cell of that grid matches. The component then declares the prop with PropTypes and a default:

```js
Button.propTypes = {
  variant: PropTypes.oneOf(['default', 'primary', 'success', 'warning'])
};

Button.defaultProps = {
  variant: 'default',
};
```

And it is used as <Button/>, <Button variant="primary"/>, and so on.

The reason this is worth having is that the two axes are independent. Without it, a component with four variants in two modes either needs eight separate values in a global theme object, or a nested lookup written by hand at every use site. The variants helper makes the combination a single declaration that lives next to the component.

## The repository, and how old the dependencies are

The top level entries show a package built with the tooling of the mid 2010s, and that is worth knowing before you reach for it.

There is index.js, the implementation, and index.js.flow with a .flowconfig, so the package ships Flow types. There is a test.js, an example/ directory with index.html, index.js, and src/, and a __snapshots__/ directory, which is the Jest snapshot test output. The build is rollup, with rollup.config.js, and the build script runs rm -rf dist and then rollup twice, once normally and once with NODE_ENV=production, and the published files list includes dist/styled-theming.js and dist/styled-theming.min.js alongside the source files. The prepublish script runs the build.

The dependency versions are the giveaway. The dev dependencies are React 15.6.1, react-dom 15.6.1, react-test-renderer 15.6.1, styled-components 2.1.1, jest 20.0.4, rollup 0.45.2, and flow-bin 0.51.0, with babel 6 era presets. The PropTypes and defaultProps usage in the variants example is also of that vintage, since React 18 removed defaultProps from function components.

So the package is small, well documented, and built on assumptions that predate the current React. The theme function itself is just an interpolation, so it may well still work with a modern styled-components, since the contract it depends on is the ThemeProvider and the props.theme object. But that is an inference from the shape of the code rather than something the documentation claims, and the package manifest does not indicate any newer release. The last push to the repository was on 2026-06-10, so something has been touched, but the version number has stayed at 2.2.0 and there are no GitHub releases to track.

## Conclusion

Adopt styled-theming if you use styled-components and want per-mode values declared next to the component rather than in a single global theme object. Do not adopt it if your project already has a theming layer that resolves modes, since this would be a second mechanism. Verify first that the styled-components version you use still supports the ThemeProvider contract this package assumes, since the package pins a much older styled-components in its dev dependencies.

## FAQ

### What does styled-theming add to styled-components?

It adds a theme(name, values) function that returns an interpolation you can use in a styled component. The values object holds one entry per theme mode, and the ThemeProvider selects which one applies, so a component declares its per-mode values locally instead of reading them from a global theme object.

### Can theme values be functions instead of plain CSS values?

Yes. The values can be any CSS value, and they can also be functions that return CSS values, for example light: props => props.theme.userProfileAccentColor.light. The ThemeProvider theme prop accepts either strings or getter functions, so the mode itself can be computed rather than hardcoded.

### What is theme.variants for?

It creates variants of the same component selected by an additional prop. The first argument is the theme key, the second is the prop name, and the third maps each variant to a value per mode, so one component declaration covers both the light and dark axes and the variant prop.

### Can a styled-theming value be a whole block of CSS?

Yes. The values are passed through like any other styled-components interpolation, so you can use the css helper to give each mode a whole block of styles with their own interpolations, which is how a background and its foreground can flip together.

### Is styled-theming still maintained?

The last push to the repository was on 2026-06-10, but the version is still 2.2.0, there are no GitHub releases, and the dev dependencies pin React 15, styled-components 2.1.1, and Jest 20, so the package was built against a much older stack than current projects use.

## Sources

- [Issues](https://github.com/styled-components/styled-theming/issues)
- [License: MIT](https://github.com/styled-components/styled-theming/blob/master/LICENSE)
- [README](https://github.com/styled-components/styled-theming/blob/master/README.md)
- [styled-components/styled-theming on GitHub](https://github.com/styled-components/styled-theming)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/styled-components-styled-theming
