useCssVar (React)

Set, get and remove a CSS custom property from the comfort of a React component. This could result in slightly more performant code when you're setting the style property directly since React will re-run your component fewer times.

typescriptjavascript
import { useMemo, useEffect } from 'react'
 
type UseCssVarProps = {
  name: `--${string}`
  root?: HTMLElement
}
 
type CssVarControls = {
  set: (value: string) => void
  get: () => string
  remove: () => void
}
 
const defaultRoot = typeof document !== 'undefined' ? document.body : undefined
 
export const useCssVar = ({
  name,
  root = defaultRoot!,
}: UseCssVarProps): CssVarControls => {
  const controls: CssVarControls = useMemo(
    () => ({
      set: value => root.style.setProperty(name, value),
      get: () => root.style.getPropertyValue(name),
      remove: () => root.style.removeProperty(name),
    }),
    [name, root]
  )
 
  useEffect(() => {
    return () => controls.remove()
  }, [controls])
 
  return controls
}
import { useMemo, useEffect } from 'react'
 
const defaultRoot = typeof document !== 'undefined' ? document.body : undefined
 
export const useCssVar = ({ name, root = defaultRoot }) => {
  const controls = useMemo(
    () => ({
      set: value => root.style.setProperty(name, value),
      get: () => root.style.getPropertyValue(name),
      remove: () => root.style.removeProperty(name),
    }),
    [name, root]
  )
 
  useEffect(() => {
    return () => controls.remove()
  }, [controls])
 
  return controls
}

Info

  • We use useMemo, so that if you follow hook rules and use the helpers in a function inside a useEffect , useCallback, etc, you won't have code (re-)running unnecessarily.

  • If you don't want the variable to be removed when the hook is no longer used, you can either remove the useEffect, or add an extra prop and conditionally return a cleanup function in the useEffect.

  • This hook doesn't use useState since it would nullify the performance aspect, and I didn't feel the need to be notified when the variable changed on the root. You could use MutationObserver if you wanted to know if the variable was updated on the root.

Demo

If you open up your browser's devtools, find the <main> element and look at its style attribute, you'll see the --example-css-var CSS variable change as you change the input's value or press the button.

The image's rotation is handled by styling it with transform: rotate(calc(var(--example-css-var, 45) * 1deg)).

Created 04/05/22Updated 07/08/23
Found a mistake, or want to suggest an improvement? Source on GitHub here
and see edit history here