In my recent project, I encountered an interesting challenge when trying to use CSS custom properties (also known as CSS variables) in my React components. TypeScript was throwing an error that looked something like this:
Object literal may only specify known properties, and '--hover-color'
does not exist in type 'Properties<string | number, string & {}>'
This error was preventing me from using custom CSS properties in my inline styles, which was crucial for creating dynamic, theme-based styles in my React components.
TypeScript's type definitions for React's CSSProperties
interface didn't
include support for custom CSS properties. This meant that while the code would
work at runtime, TypeScript would complain during compilation.
To solve this, I extended the CSSProperties
interface in React to accept
custom properties. Here's what I added:
declare module 'react' {
interface CSSProperties {
[key: `--${string}`]: number | string;
}
}
This simple addition allows me to use custom CSS properties in my inline styles without TypeScript complaints.
Here's how I implemented this solution:
- I created a new file
src/types/react-augmentations.d.ts
with the following content:
import 'react';
declare module 'react' {
interface CSSProperties {
[key: `--${string}`]: number | string;
}
}
- In
tsconfig.json
, I added the types directory to theinclude
array:
"include": [
// ... other entries
"src/types/**/*.d.ts"
],
Now, I can easily use custom CSS properties in my React components like this:
<div
style={{
'--hover-color': `var(${color})`,
'backgroundColor': isHovered ? `var(--hover-color)` : 'transparent',
}}
>
This div uses custom CSS properties
</div>
I like to work with TypeScript and this solution allows me to properly use CSS variables within JSX with these benefits:
- Type Safety: TypeScript now recognizes custom CSS properties as valid.
- Dynamic Styling: I can easily change styles based on component state or props.
- Theme Support: Implementing theme switching becomes much easier.
- Consistency: I can use the same custom properties in both CSS and JS.
This small change has significantly improved my workflow when working with CSS custom properties in React components. It bridges the gap between CSS and TypeScript, allowing for more flexible and dynamic styling while maintaining type safety.
Another approach I've found is that we can make it more type safe by allowing specific CSS variables. Like this:
declare module 'react' {
interface CSSProperties {
'--theme-color'?: 'black' | 'white';
'--accent-color'?: string;
}
}
This approach however feels too restrictive and I think it's better to just let CSS be more freely in this case.
Happy coding!
References: