Tooling idea: collect all the available CSS selectors:
const selectors = new Set<string>(document.styleSheets.reduce<string[]>(
(acc, { rules }) => [...acc, ...rules.map(({ selectorText }) => selectorText)],
[]
))
export function assertSelectors(...args: string[]) {
args.forEach((selector) => {
if (!selectors.has(selector)) {
throw new Error(`Selector "${selector}" doesn't exist in any stylesheet`)
}
})
}
Then, in a component:
import React from 'react'
import clsx from 'clsx'
import { assertSelectors } from '../helpers/selectors'
export const selectors = {
root: 'btn',
text: 'btn-text'
}
export const Button: React.FC<ButtonProps> ({ className, children, ...rest }) => {
// Assert selectors for development builds here such that missing styles cause
// immediate runtime errors. This could also be a higher-order function.
if (process.env.NODE_ENV === 'development') {
assertSelectors(selector.root, selector.text)
}
return (
<button className={clsx(selectors.root, className)} {...rest}>
<span class={selector.text}>{children}</span>
</button>
)
}
Then, in a component's stylesheet these could be transformed to match the export:
.${selectors.root} {
background: crimson;
border: 1px solid transparent;
color: red;
cursor: pointer;
display: inline-block;
font: inherit;
padding: 1em 1.25em;
&:focus,
&:hover {
background: firebrick;
}
&:active {
background: darkred;
}
}
.${selectors.text} {
font-weight: 500;
}