Theme Party is an unstyled & unopinionated method of providing an interchangeable theme to React apps. You can structure your theme objects however you like, and use any styling engine. Themes can override primitive values (such as colors & fonts) as well as swap out entire components for more complex layout differences between themes.
Theme Party has the following major exports:
ThemeParty
ThemeProvider
useTheme
costumed
yarn add theme-party
Create your first ThemeParty
instance. This is generally where you should define the shape of your theme
and the types & names of design tokens/primitives you will use. This an example, you can use any shape or token names.
If you're using TypeScript, the instance will infer the type of your theme object.
import { ThemeParty } from 'theme-party';
export const myThemeParty = new ThemeParty({
color: {
primary: '#85FFC7',
secondary: '#297373',
accent: '#FF8552',
ghost: '#E6E6E6',
text: '#39393A',
link: theme => theme.color.primary,
},
spacing: {
sm: '4px',
md: '8px',
lg: '16px',
},
typography: {
sans: 'Arial',
serif: 'Georgia',
},
});
This instance can act as your default theme.
If you're using TypeScript, make your custom theme shape available to other theme-party
utils by adding to the above:
declare module 'theme-party' {
interface UserTheme {
default: typeof myThemeParty;
}
}
Create another theme by extending your first with overrides.
const myOtherTheme = myThemeParty.createTheme({
color: {
primary: '#CE2D4F', // this will update both the primary color and the link color (since link points to primary)
secondary: theme => theme.color.accent,
},
});
import { ThemeProvider } from 'theme-party';
export function App() {
const [theme, setTheme] = useState(myThemeParty);
return (
<ThemeProvider theme={theme}>
// ...
<button onClick={() => setTheme(myOtherTheme)}>
Change theme
</button>
</ThemeProvider>
);
}
ThemeProvider
takes a ThemeParty
instance as its theme
prop.
It can be nested further down in your component hierarchy to override the theme for its children.
Use the useTheme
hook to retrieve your active theme's values.
This can be combined with any method of styling such as Emotion or Tailwind.
import { useTheme } from 'theme-party';
export function Link({ children }) {
const theme = useTheme();
return (
<a style={{ color: theme.color.link }}>
{children}
</a>
);
}
Create a "costumed" component containing your default markup.
import { costumed } from 'theme-party';
interface Props {
name: string;
}
export const MyComponent = costumed<Props>(function MyComponent({ name }) {
return <h1>Hello, {name}</h1>;
});
In your theme, replace the component with another by calling useComponent
with the original costumed component above and a replacement component that matches the same props;
myOtherTheme.useComponent(MyComponent, ({ name }) => (
<div>
<img src={`/generate-img?name=${name}`} />
</div>
));
Then render the original component anywhere in your app. If the active theme has its own version of the component, it will be rendered in its place.
function Page() {
return (
<MyComponent name="World" />
);
}
Sometimes, you might want to override a single theme value, while inheriting the rest of the current theme.
import { ThemeOverride, ThemePartyConfig } from 'theme-party';
const override: ThemePartyConfig = { color: { link: 'blue' } };
function Component() {
return (
<ThemeOverride value={override}>
<Link>Click me</Link>
</ThemeOverride>
);
}
This creates a temporary theme that preserves the rest of the values of the currently selected theme.
Note: the object passed to value must be stable across renders. Either use a constant or memoize the object.
In pull request branch, run
yarn version [patch|minor|major] --deferred
and commit yarn version file. When PR is merged, the package version will be updated accordingly. See Yarn Release Workflow for more details.