Make your component's class-names reactive to your component state. Ideally used in conjunction with a utility-CSS framework like Tailwind or Tachyons.
npm install use-utility-classesoryarn add use-utility-classes
Pass your props to the useUtilityClasses hook, then pass conditions to the function it returns to conditionally render certain props:
import useUtilityClasses from 'use-utility-classes' const Component = ({ color }) => { // Watch the value for the prop `color` const setClassName = useUtilityClasses({ color }) // Set the class `text-red-500` when the value is `red` const className = setClassName({ when: { color: 'red' }, use: 'text-red-500' }) return <span className={className} /> }<Component color='red' /> // <span class="text-red-500" /> <Component color='blue' /> // <span />You can add multiple criteria:
import useUtilityClasses from 'use-utility-classes' const Component = ({ color, isDisabled }) => { // Watch the value for the following props: const setClassName = useUtilityClasses({ color, isDisabled }) // Only set the class when the color is red *and* the component is not disabled const className = setClassName({ when: { color: 'red', isDisabled: false }, use: 'text-red-500' }) return <span className={className} /> }<Component color='red' isDisabled={true} /> // <span class="text-red-500" /> <Component color='red' isDisabled={false} /> => <span />You can also pass more than one condition to the setClassName function:
import useUtilityClasses from 'use-utility-classes' const redEnabledVariant = { when: { color: 'red', isDisabled: false }, use: 'text-red-500' } const redDisabledVariant = { when: { color: 'red', isDisabled: true }, use: 'text-red-300 cursor-not-allowed' } const Component = ({ color, isDisabled }) => { const setClassName = useUtilityClasses({ color, isDisabled }) const className = setClassName(redEnabledVariant, redDisabledVariant) return <span className={className} /> }<Component color='red' isDisabled={false} /> // <span class="text-red-500" /> <Component color='red' isDisabled={true} /> // <span class="text-red-300 cursor-not-allowed" />For class-names that should always display, just pass a string:
import useUtilityClasses from 'use-utility-classes' const redEnabledVariant = { when: { color: 'red', isDisabled: false }, use: 'text-red-500' } const redDisabledVariant = { when: { color: 'red', isDisabled: true }, use: 'text-red-300 cursor-not-allowed' } const defaultClasses = 'font-semibold text-xs uppercase' const Component = ({ color, isDisabled }) => { const setClassName = useUtilityClasses({ color, isDisabled }) const className = setClassName( redEnabledVariant, redDisabledVariant, defaultClasses ) return <span className={className} /> }<Component color='red' isDisabled={true} /> // <span class="text-red-300 cursor-not-allowed font-semibold text-xs uppercase" /> <Component color='red' isDisabled={false} /> // <span class="text-red-500 font-semibold text-xs uppercase" /> <Component /> // <span class="font-semibold text-xs uppercase" />An HOC helper is also included in this package which will pass the hook via props:
import withSetClassName from 'use-utility-classes/react' const Component = props => { const className = props.setClassName({ when: { color: 'red', isDisabled: false }, use: 'text-red-500' }) return <span className={className} /> } const WrappedComponent = withSetClassName(Component /*, { debug: true, prefix: 'tw-' } */)<WrappedComponent color='red' isDisabled={false} /> // <span class="text-red-500"></span>You can pass a prefix option if you'd like one appended to your classes:
import useUtilityClasses from 'use-utility-classes' const Component = props => { const setClassName = useUtilityClasses(props, { prefix: 'tw-' }) const className = setClassName('border-black bg-black hover:bg-gray-700 text-white') return <button className={className} /> }<Component /> // <span class="tw-border-black tw-bg-black hover:tw-bg-gray-700 tw-text-white" />You can pass an option to make the classes more legible while you're doing development:
import useUtilityClasses from 'use-utility-classes' const Component = props => { const setClassName = useUtilityClasses(props, { debug: true }) const className = setClassName( 'uppercase text-xs font-semibold tracking-wide', { when: { isLoading: true }, use: 'text-gray-300 cursor-not-allowed' }, { when: { isLoading: false }, use: 'text-black cursor-pointer' } ) return <span className={className} /> }The outputs of your conditions will be listed and marked as enabled or disabled:
<Component isLoading={false} /> /* <span class=" • uppercase text-xs font-semibold tracking-wide ×⠀text-gray-300⠀cursor-not-allowed • text-black cursor-pointer"></span> */ <Component isLoading={true} /> /* <span class=" • uppercase text-xs font-semibold tracking-wide • text-gray-300 cursor-not-allowed ×⠀text-black⠀cursor-pointer"></span> */