hook-style v1.5.1
hook-style
Style your React components with Hooks
Table of contents
Getting started
npm install hook-style
import { useStyle } from 'hook-style';
import React from 'react';
import ReactDOM from 'react-dom';
function Paragraph({ color, ...props }) {
const cn = useStyle`
padding: 1rem;
background-color: yellow;
color: ${color};
`;
return <p className={cn} {...props} />;
}
ReactDOM.render(
<div>
<Paragraph color="magenta">I'm magenta</Paragraph>
<Paragraph color="blue">I'm blue</Paragraph>
</div>,
document.getElementById('root')
);
<!-- In <head /> -->
<style>
.gtXozB {
padding: 1rem;
background-color: yellow;
color: var(--gtXozB-0);
}
</style>
<style>
.gqAIHm {
--gtXozB-0: blue;
}
</style>
<style>
.eKigJM {
--gtxozb-0: magenta;
}
</style>
<!-- In <div id="root" /> -->
<div>
<p class="gtXozB gqAIHm">I'm blue</p>
<p class="gtXozB eKigJM">I'm magenta</p>
</div>
<!-- In <head /> -->
<style>
.efNhRD {
padding: 1rem;
background-color: yellow;
color: blue;
}
</style>
<style>
.kGJulO {
padding: 1rem;
background-color: yellow;
color: magenta;
}
</style>
<!-- In <div id="root" /> -->
<div>
<p class="efNhRD">I'm blue</p>
<p class="kGJulO">I'm magenta</p>
</div>
The amount of CSS generated is larger, but it acheives the same effect.
If you want to use this output in all browsers, use the useStyleWithoutCustomProps
hook.
On the other hand, if you can guarantee your app wont be run in older browsers, you can skip the support check by using the useStyleWithCustomProps
hook directly.
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 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 { useStyle } from 'hook-style';
import React from 'react';
import ReactDOM from 'react-dom';
function Button({ primary, ...props }) {
const cn = useStyle`
display: inline-block;
padding: 0.5rem 0;
width: 10rem;
background-color: ${primary ? 'magenta' : 'yellow'};
color: ${primary ? 'yellow' : 'magenta'};
border: 0.125rem solid ${'magenta'};
@media (min-width: 32rem) {
padding: 0.75rem 0;
width: 15rem;
font-size: 1.5rem;
}
&:focus {
color: #000;
border-color: #000;
}
`;
return <button className={cn} {...props} />;
}
ReactDOM.render(
<div>
<Button>Standard</Button>
<Button primary>Primary</Button>
</div>,
document.getElementById('root')
);
useTheme
The useTheme
hook allows you to read the theme context from the nearest <ThemeProvider />
ancestor:
import { useStyle, useTheme, ThemeProvider } from 'hook-style';
import React from 'react';
import ReactDOM from 'react-dom';
function Paragraph({ ...props }) {
const { fg, bg } = useTheme();
const cn = useStyle`
padding: 1rem;
background-color: ${bg};
color: ${fg};
`;
return <p className={cn} {...props} />;
}
ReactDOM.render(
<ThemeProvider theme={{ fg: 'magenta', bg: 'yellow' }}>
<Paragraph>I'm magenta on yellow</Paragraph>
</ThemeProvider>,
document.getElementById('root')
);
Combine this with React's useState
hook, and you'll be able to modify the theme on the fly:
import { useStyle, useTheme, ThemeProvider } from 'hook-style';
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
function Button({ primary, ...props }) {
const { fg, bg } = useTheme();
const cn = useStyle`
padding: 0.5rem;
background-color: ${primary ? fg : bg};
color: ${primary ? bg : fg};
border: 0.125rem solid ${fg};
`;
return <button className={cn} {...props} />;
}
function App() {
const [theme, setTheme] = useState({
fg: 'magenta',
bg: 'yellow'
});
const invertTheme = () =>
setTheme({
bg: theme.fg,
fg: theme.bg
});
return (
<ThemeProvider theme={theme}>
<div>
<Button onClick={invertTheme}>Invert Theme</Button>
<Button onClick={invertTheme} primary>
Invert Theme
</Button>
</div>
</ThemeProvider>
);
}
ReactDOM.render(<App />, document.getElementById('root'));