How to apply styles based on props?
Asked Answered
R

3

5

I'm using React and Material-ui, and currently I'm doing something like the code below.
Is there a better way?

For instance, is there a function that allows you to access 'props' within the "styles" jss object below the component that is eventually injected into the component with withStyles() without having to do all this ugly inline styling?

import React from 'react';
import {
  MaterialComponentOne,
  MaterialComponentTwo,
  MaterialComponentThree,
} from '@material-ui/core';

function MyPureComponent(props) {
  return (
    <MaterialComponentOne
      style={
        props.type === 'secondary'
          ? {
              css_property: 'css_value1',
            }
          : {
              css_property: 'css_value2',
            }
      }
      className={props.classes.MaterialComponentOne}
      position="static"
    >
      <MaterialComponentTwo>
        <MaterialComponentThree
          style={
            props.type === 'secondary'
              ? {
                  css_property: 'css_value1',
                }
              : {
                  css_property: 'css_value2',
                }
          }
          variant="title"
          className={props.classes.MaterialComponentThree}
        >
          {props.title}
        </MaterialComponentThree>
      </MaterialComponentTwo>
    </MaterialComponentOne>
  );
}

const styles = {
  MaterialComponentOne: {
    css_property: 'css_value',
    css_property: 'css_value',
  },
  MaterialComponentTwo: {
    css_propery: 'css_value',
  },
};

export default withTheme()(withStyles(styles)(MyPureComponent));

thanks.

Rocca answered 10/8, 2018 at 7:51 Comment(1)
Why do you have in MaterialComponentOne style object two css property with the same key?Coney
I
4

You may use clsx library which comes with Material UI or classnames library for conditionally joining classNames together. The example below is shown using classnames library, you may also use clsx library to achieve the same result.

import React from 'react';
import {
  MaterialComponentOne,
  MaterialComponentTwo,
  MaterialComponentThree,
} from '@material-ui/core';
import classNames from "classnames"

function MyPureComponent(props) {
  return (
    <MaterialComponentOne
      position="static"
      className={classNames(
        props.classes.MaterialComponentOne, 
        {[props.classes.classOne]: props.type === 'secondary'}, 
        {[props.classes.classTwo]: props.type !== 'secondary'}
      )}

    >
      <MaterialComponentTwo>
        <MaterialComponentThree
          variant="title"
          className={classNames(
            props.classes.MaterialComponentThree, 
            {"props.classes.classOne": props.type === 'secondary'}, 
            {"props.classes.classTwo": props.type !== 'secondary'}
          )}
        >
          {props.title}
        </MaterialComponentThree>
      </MaterialComponentTwo>
    </MaterialComponentOne>
  );
}

const styles = {
  MaterialComponentOne: {
    css_property: 'css_value',
    css_property: 'css_value',
  },
  MaterialComponentTwo: {
    css_propery: 'css_value',
  },
  classOne: {
    css_property: 'css_value',
  },
  classTwo: {
    css_property: 'css_value'
  }
};

export default withTheme()(withStyles(styles)(MyPureComponent));



Usage


The classNames function takes any number of arguments which can be a string or object. The argument 'foo' is short for { foo: true}. If the value associated with a given key is falsy, that key won't be included in the output.

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
Improvisation answered 10/8, 2018 at 9:1 Comment(5)
I tend to prefer this solution as id does not introduce another styling framework like styled-components.Uzbek
@Andrew you probably wanted to use computed property names like { [props.classes.classOne]: true } instead of a string {"props.classes.classOne": true}Sheikh
Hi @Idan Dagon, thank you for the suggestion, but I do not know the differences between them, can you help to explain it? Thank you :)Improvisation
@AndrewLam just run your code and see that you have a bug while using classNames. and read about "computed property names"Sheikh
@IdanDagan Thank you for the correction and explanation :)Improvisation
S
2

You can use styled-components.

Example based on the docs Adapting based on props:

import styled from 'styled-components';

const Button = styled.button`
  background: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};
`;

function MyPureComponent(props) {
  return (
    <div>
      <Button>Normal</Button>
      <Button primary>Primary</Button>
    </div>
  );
}
Sheikh answered 10/8, 2018 at 8:17 Comment(0)
D
2

A natural way is using createStyles hook alongside with makeStyles and useStyles. You can use the prop name inside the element you are styling by making it an arrow function that returns the styling. In addition, you can also style other elements inside the createStyles hook. This took me some time, I hope anyone finds it useful. ✨🔥

Here is the code also provided as an answer to another question: (https://mcmap.net/q/335942/-how-to-use-39-theme-39-and-39-props-39-in-makestyles)

import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";

...
...


const classes = useStyles();

...
...

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: propName => ({
      border: "none",
      boxShadow: "none",
      cursor: propName ? "pointer" : "auto",
      width: "100%",
      backgroundColor: "#fff",
      padding: "15px 15px"
    }),

    updated: {
      marginTop: 12,
      fontWeight: 400,
      color: "#939393"
    }
  })
);
Disconcerted answered 10/9, 2021 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.