Neilson Gamble
Neilson Gamble

Reputation: 53

How to apply styles based on props?

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.

Upvotes: 5

Views: 5241

Answers (3)

klevisx
klevisx

Reputation: 182

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://stackoverflow.com/a/69137307/10968401)

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"
    }
  })
);

Upvotes: 2

Andrew Lam
Andrew Lam

Reputation: 3804

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'

Upvotes: 4

Idan Dagan
Idan Dagan

Reputation: 11575

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>
  );
}

Upvotes: 2

Related Questions