How to define css variables in style attribute in React and typescript

ReactjsTypescriptJsxTsx

Reactjs Problem Overview


I want to define jsx like this:

<table style={{'--length': array.lenght}}>
   <tbody>
      <tr>{array}</tr>
   </tbody>
</table>

and I use --length in CSS, I also have cells that have --count that shows count using CSS pseudo selector (using the counter hack).

but typescript throws error:

TS2326: Types of property 'style' are incompatible.
  Type '{ '--length': number; }' is not assignable to type 'CSSProperties'.
    Object literal may only specify known properties, and ''--length'' does not exist in type 'CSSProperties'.

is it possible to change type of style attribute to accept CSS variable (custom properties) or is there a way to force any on style object?

Reactjs Solutions


Solution 1 - Reactjs

Like this:

function Component() {
  const style = { "--my-css-var": 10 } as React.CSSProperties;
  return <div style={style}>...</div>
}

Or without the extra style variable:

function Component() {
  return <div style={{ "--my-css-var": 10 } as React.CSSProperties} />
}

Solution 2 - Reactjs

If you go to the definition of CSSProperties, you'll see:

export interface CSSProperties extends CSS.Properties<string | number> {
    /**
     * The index signature was removed to enable closed typing for style
     * using CSSType. You're able to use type assertion or module augmentation
     * to add properties or an index signature of your own.
     *
     * For examples and more information, visit:
     * https://github.com/frenic/csstype#what-should-i-do-when-i-get-type-errors
     */
}

That link gives examples of how to solve the type error by augmenting the definition of Properties in csstype or casting the property name to any.

Solution 3 - Reactjs

You could add a type assertion to the variable. i.e. {['--css-variable' as any]: value }

<table style={{['--length' as any]: array.lenght}}>
   <tbody>
      <tr>{array}</tr>
   </tbody>
</table>

Solution 4 - Reactjs

Casting the style to any defeats the whole purpose of using TypeScript, so I recommend extending React.CSSProperties with your custom set of properties:

import React, {CSSProperties} from 'react';

export interface MyCustomCSS extends CSSProperties {
  '--length': number;
}

By extending React.CSSProperties, you will keep TypeScript's property checking alive and you will be allowed to use your custom --length property.

Using MyCustomCSS would look like this:

const MyComponent: React.FC = (): JSX.Element => {
  return (
    <input
      style={
        {
          '--length': 300,
        } as MyCustomCSS
      }
    />
  );
};

Solution 5 - Reactjs

you can simply put this module declaration merge using string templates at the top of the file or in any .d.ts file, then you will be able to use any CSS variable as long it starts '--' and that is string or number

import 'react';

declare module 'react' {
    interface CSSProperties {
        [key: `--${string}`]: string | number
    }
}

for example

<div style={{ "--value": percentage }} />

Solution 6 - Reactjs

import "react";

type CustomProp = { [key in `--${string}`]: string };
declare module "react" {
  export interface CSSProperties extends CustomProp {}
}

put this in your global.d.ts file

Solution 7 - Reactjs

I would like to add a different approach by using document.body.style.setProperty, and maybe if your css variable will be affected by certain props you can put it in a useEffect like this:

useEffect(() => {
    document.body.style.setProperty(
      "--image-width-portrait",
      `${windowSize.width - 20}px`
    );
}, [windowSize])

Later inside your css file you can call it like this:

width: var(--image-width-portrait);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjcubicView Question on Stackoverflow
Solution 1 - ReactjsixrockView Answer on Stackoverflow
Solution 2 - ReactjsMatt McCutchenView Answer on Stackoverflow
Solution 3 - ReactjsCarlos A. CabreraView Answer on Stackoverflow
Solution 4 - ReactjsBenny NeugebauerView Answer on Stackoverflow
Solution 5 - ReactjssaulpalvView Answer on Stackoverflow
Solution 6 - ReactjsBeanBroView Answer on Stackoverflow
Solution 7 - ReactjsKiraView Answer on Stackoverflow