
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
css-vars-hook
Advanced tools
css-vars-hook contains React hooks to set and manipulate CSS custom properties from React component.
css-vars-hook contains React hooks to set and manipulate CSS custom properties (variables).
npm install css-vars-hook
css-vars-hook exposes two hooks: useRootTheme, useLocalTheme. Both of them provide developer a bridge between React Component state and CSS Custom Properties.
useRootThemeuseRootTheme applies application level themes. API consists of two elements: the hook itself and RootThemeProvider component which acts as :root selector. Directly applying theme to the :root is not compatible with Server side rendering (SSR).
In order to set global theming you need to wrap your application with RootThemeProvider on highest possible level.
// App.js
import React from 'react';
import {RootThemeProvider} from 'css-vars-hook';
// Theme object contains dictionary of CSS variables you will use later in your application
const theme = {
boxColor: 'purple',
borderColor: 'violet',
}
export const App = () => (
<RootThemeProvider
theme={theme}>
{/*...*/}
</RootThemeProvider>
);
To avoid unnecessary reconciliations and re-renders theme object has to preserve referential equality during component lifecycle.
Arbitrary objects are recreated every time React component reconciles. Avoid this when defining theme object.
// Don't do this!!!
const Component: FC = () => {
//...
const theme = {
foo: 'bar'
}
return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}
// Don't do this!!!
const Component: FC = () => {
//...
return <RootThemeProvider theme={{ foo: 'bar' }}>{/*...*/}</RootThemeProvider>
}
Set theme object externally to Component or wrap with useMemo.
// Correct!
const theme = {
foo: 'bar'
}
const Component: FC = () => {
return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}
// Correct! Theme will preserve until foo property change
const Component: FC<{foo: string}> = ({foo}) => {
const theme = useMemo(() => ({foo}), [foo])
return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}
Theme changing methods (setTheme, setVariable, removeVariable) are implemented as effects. They will apply after component re-render. You'll have to wrap the side effect with useEffect or put in inside callback to move it out of the rendering calculation.
// Component.jsx
import React, { useEffect, useCallback } from "react";
import { useRootTheme } from 'css-vars-hook';
const theme = {
boxColor: 'red',
borderColor: 'green',
}
const Component = () => {
const { setTheme, setVariable, removeVariable } = useRootTheme();
// Set theme value inside useEffect hook
useEffect(() => {
// Theme changing effects can be applied like this. The change will happen after render.
setTheme(theme);
}, [theme, setTheme])
// Set theme value inside callback
const handleVariable = useCallback(() => {
setVariable('boxColor', 'pink');
}, [])
return <button onClick={handleVariable}>Change variable</button>;
}
//...
const Component = () => {
const { setTheme } = useRootTheme();
// This will not work!
setTheme(theme)
//...
}
The reason this code isn’t correct is that it tries to do something with the DOM node during rendering. In React, rendering should be a pure calculation of JSX and should not contain side effects like modifying the DOM. Moreover, when Component is called for the first time, its DOM does not exist yet, so there is no theme container to operate with.
Developers can provide theme type to useRootTheme hook as a TypeScript Generic.
import { FC } from "react";
type Theme = {
boxColor: 'yellow' | 'blue';
borderColor: string;
};
const themeYellow: Theme = {
boxColor: 'yellow',
borderColor: 'blue',
};
const Component: FC = () => {
const {setTheme, getTheme, setVariable} = useRootTheme<Theme>();
const doSomething = () => {
// theme value will be properly typed this way
console.log('root theme', getTheme().boxColor);
};
//...
}
CSS variables set by RootThemeProvider are available globally across all application.
// Component.css
.box {
background: var(--boxColor);
border: 1px solid var(--borderColor)
}
import {useRootTheme} from 'css-vars-hook';
const {
/** Get current theme */
getTheme,
/** Get variable value within active theme */
getVariable,
} = useRootTheme();
console.log(getVariable('boxColor')) // => 'purple'
console.log(getTheme()) // => theme object
useLocalThemeuseLocalTheme applies theme locally to the wrapped React components.
In order to set local theme you need to wrap your component with LocalRoot component which is returned by useLocalTheme hook.
import { useLocalTheme } from 'css-vars-hook';
import { useCallback } from "react";
const theme = { boxColor: 'yellow' };
const darkTheme = {boxColor: 'darkYellow'};
const Component = () => {
const { LocalRoot, setTheme } = useLocalTheme();
const setDarkMode = useCallback(() => {
setTheme(darkTheme)
}, []);
return <LocalRoot theme={theme}>{/*...*/}</LocalRoot>
}
Outside different wrapping strategies this hook is similar to useRootTheme.
LocalRoot elementBy default LocalRoot is rendered as a div HTMLElement. You can provide custom element type (button, span, e. t. c.) by changing as prop of LocalRoot.
import {useLocalTheme} from 'css-vars-hook';
const theme = {boxColor: 'yellow'};
const darkTheme = {boxColor: 'darkYellow'};
const Component = () => {
const {LocalRoot: Button, setTheme} = useLocalTheme();
const setDarkMode = useCallback(() => {
setTheme(darkTheme)
}, [])
return (
<Button
theme={theme}
as="button"
onClick={setDarkMode}>
Set dark mode
</Button>
)
}
Local theme type is inferred from corresponding LocalRoot prop.
FAQs
css-vars-hook contains React hooks to set and manipulate CSS custom properties from React component.
We found that css-vars-hook demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.