Style your React components with Hooks
Table of contents
- Getting started
- API
- Hooks
- Components
- Utilities
- About the project
Getting started
npm install styled-hooks
import React from 'react';import ReactDOM from 'react-dom';import useStyle from 'styled-hooks'; { const cn = useStyle` padding: 1rem; background-color: yellow; color: ; `; return <p = />;} ReactDOM;
The rendered page will look like this:
<!-- In <head /> --> <!-- In <div id="root" /> --> I'm blue I'm magenta
“Wait. Those are CSS Custom Properties. I thought they didn't work everywhere?”
Don't worry! Styled Hooks will render the following in browsers that aren't up to scratch:
<!-- In <head /> --> <!-- In <div id="root" /> --> I'm blue I'm magenta
The amount of CSS generated is larger, but it acheives the same effect.
Note: You can still interpolate large portions of your CSS as strings—Custom Properties only come into effect when you attempt to interpolate CSS property values.
API
useStyle
The useStyle
hook is a tagged template that expects CSS & dynamic values, and returns a className
you can use in your component.
The hook will memoise the CSS of each unique style variant, and inject it into your document's <head>
, taking advantage of CSS Custom Properties (if your browser suports them) to reduce style replication.
Style injection happens during the browser's layout phase, so your components will always be painted fully-styled.
Thanks to stylis
, you can use some basic nesting and media queries:
import React from 'react';import ReactDOM from 'react-dom';import useStyle from 'styled-hooks'; { const cn = useStyle` display: inline-block; padding: 0.5rem 0; width: 10rem; background-color: ; color: ; border: 0.125rem solid ; @media (min-width: 32rem) { padding: 0.75rem 0; width: 15rem; font-size: 1.5rem; } &:focus { color: #000; border-color: #000; } `; return <button = />;} ReactDOM;
Theming
In the example above, the dynamic styling is based on component properties, but what if we wanted to have a consistent theme throughout our app? Assuming your component is descendant of a ThemeProvider
component, you're able to take advantage of a couple of the useStyle
hook's additional features...
The first is an interpolation syntax familiar to anyone who's used SASS:
;;; { const cn = useStyle` padding: 1rem; background-color: #{bg}; color: #{fg}; `; return <p className=cn ...props />;} ReactDOM
To access a property of the theme you're providing, just place it between #{
and }
braces. The usual template string interpolation still works, so you're still able to create styles based on your component props.
The interpolation syntax allows you to access nested properties too. Imagine your theme looked like this:
colors: fg: 'magenta' bg: 'yellow' space: '0' '0.25rem' '0.5rem' '1rem' '2rem' '4rem' '8rem' '16rem' '32rem'
You're able to access it like this:
{ const cn = useStyle` padding: #{space.3}; background-color: #{colors.bg}; color: #{colors.fg}; @media (min-width: 480px) { padding: #{space.4}; } `; return <p className=cn ...props />;}
If you need to output different theme values based on your props, interpolate a function and it'll receive your theme as an argument:
{ const cn = useStyle` padding: 1rem; background-color: ; color: ; `; return <p className=cn ...props />;}
Going themeless
If you're styling components that don't require theming, you can opt to use an alternative hook: useThemelessStyle
. It works the same way you'd expect useStyle
to, only you can't interpolate functions (as there's no theme to pass in), or use the #{}
-style theme prop interpolation.
;;; { const cn = useThemelessStyle` font-family: ; font-weight: 200; `; return <h1 className=cn ...props />;} ReactDOM
useTheme
The useTheme
hook allows you to read theme context from the nearest <ThemeProvider />
ancestor, for use in places other than your styles:
import React from 'react';import ReactDOM from 'react-dom';import ThemeProvider useTheme from 'styled-hooks'; { const fg bg = ; return <p>`This app's foreground color is ; its background color is `</p> ;} ReactDOM;
Combine this with React's useState
hook, and you'll be able to modify the theme on the fly:
import React useState from 'react';import ReactDOM from 'react-dom';import ThemeProvider useTheme from 'styled-hooks'; { const fg bg = ; return <button > `This app's foreground color is ; its background color is ` </button> ;} { const theme setTheme = ; return <ThemeProvider => <ColorSwapper = /> </ThemeProvider> ;} ReactDOM;
ThemeProvider
This component allows you to provide theme context that can be accessed by useStyle
and useTheme
hooks anywhere in your app. Have a look at their respective examples above for basic usage.
ThemeProvider
s have a single property, theme
which can be set to either an object or a merge function (explained further below).
import React from 'react';import ReactDOM from 'react-dom';import ThemeProvider from 'styled-hooks';import App from './App'; const theme = fg: 'magenta' bg: 'yellow'; ReactDOM;
ThemeProvider
components
Nesting When you nest ThemeProvider
components, the child theme will be merged with its parent. You can either provide an object in order to add or replace theme properties, or a function to transform the parent theme entirely.
Here's the App.js
component that is imported into the previous example:
import React from 'react';import ThemeProvider useStyle from 'styled-hooks'; { const cn = useStyle` padding: 1rem; background-color: #{bg}; color: #{fg}; `; return <p = />;} { return <div> <Paragraph> magenta on yellow</Paragraph> <ThemeProvider => <Paragraph> blue on yellow</Paragraph> </ThemeProvider> <ThemeProvider => <Paragraph> magenta on cyan</Paragraph> </ThemeProvider> </div> ;}
injectGlobal
This utility allows you to add arbitrary CSS to the document. It's useful for resets and other document-level styles.
; injectGlobal` html { font-size: 18px; } body { margin: 0; }`;
It can't be part of your app's component hierarchy, and therefore doesn't have access to theme context. You can use any interpolated values you want, but unlike hooks they won't ever become CSS Custom Properties.
About the project
- Styled Hooks is currently maintained by Colin Gourlay
- It is currently licensed under The Unlicense
- If you'd like to help out, please submit ideas & bugs to the project's issue tracker
- To contribute code and documentation, please see the contribution guide
- All contributions and project activity are subject to the project's code of conduct
Credits
Dependencies:
- stylis - The CSS parser providing auto-prefixing and SASS-like nesting
Inspiration:
Thanks:
- Glen Maddern, for giving this project a name