1

I am currently working on a NextJS based project, in which I need to use React State to determine the width of a div. Currently this is being calculated inside a .tsx file using consts and incremented when a button is clicked. The resultant width is then passed down as a prop to the component.

Right now, I'm using inline styling to set the width of the div, but I wanted to know if it was possible to pass the prop directly into the .module.css file I'm using as it will be tidier and much easier for media queries later on. Is that possible?

Also, is it possible to import variables from the media queries back into the .tsx file?

Main file:

const [width, setWidth] = React.useState(0)
const increment: number = maxWidthTop / totalRounds

export default function Labeller() {
  function clicked() {
    setWidth(width + increment)
  }
  return (
        <Progress
            width={width} />
  )}

Component file:

import styles from '../../styles/Progress.module.css'

type ProgressProps = {
    width: number;
}

export default function ProgressBar(props: ProgressProps) {
    return (
        <div className={styles.main}>
            <div className={styles.bar}>
                <div className={styles.base}></div>
                <div style={{width: `${props.width}em`}} className={styles.top}></div>
            </div>
        </div>
    )
}

1 Answer 1

1

You can't modify the css module dynamically at runtime as the css files are downloaded and parsed by the browser separately from the js. Supplying your width value using inline is styles a good way to go but you are right that it doesn't make media queries easy.

One alternative option would be to write a function that formats a css string with your width variable, and renders the output inside a style element:

import "./styles.css";

const divWidthStyles = (width: number) => `
  .${styles.top} {
    width: ${width}px;
  }

  @media only screen and (min-width: 600px) {
    .${styles.top} {
      width: ${2 * width}px;
    }
  }
`;

...

export default function ProgressBar(props: ProgressProps) {
  return (
    <div className={styles.main}>

      /* Use style element */
      <style>{divWidthStyles(props.width)}</style>

      <div className={styles.bar}>
        <div className={styles.base}></div>
        <div className={styles.top}></div>
      </div>
    </div>
  );
}

Another option would be to set a css variable using javascript, whenever width changes, by making use of useEffect(). Like so:

function ProgressBar(props: ProgressProps) {
  const { width } = props;

  const divRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (divRef.current) {
      divRef.current.style.setProperty("--width", `${width}px`);
    }
  }, [width]);

  return (
    ...
      <div
        className={"dynamic_width"}
        ref={(ref) => (divRef.current = ref)}
      ></div>
    ...
  );
}

And then making use of the variable in your css.module file like this:

.dynamic_width {
  height: 200px;
  background: red;
  width: var(--width);
}

@media only screen and (min-width: 600px) {
  .dynamic_width {
    width: calc(2 * var(--width));
  }
}

Side note; there's a library called styled-components that allows you to supply values to the styles of components easily. I find it helps to keep things very tidy and could be a more elegant solution to your problem.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much, it works perfectly now! I'll definitely look into the library you recommended too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.