Better way to use material-system with styled-components

I am trying to use the stack above to customize Material components with the props provided by the Material system (joining with styled-components). The component that I'm testing:

import React from 'react'
import Grid from '@material-ui/core/Grid'

import { spacing, sizing, color, flexbox, display } from '@material-ui/system'
import styled from 'styled-components'

const Row = styled(props => <Grid container {...props} />)`
  ${spacing}
`

export default Row

Everything on screen works very well, but an error on console appear every time that I use a material-system prop. Ex.:

<Row maxWidth='200px'>...</Row>

the following error appear on console:

Warning: React does not recognize the maxWidth prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase maxwidth instead. If you accidentally passed it from a parent component, remove it from the DOM element.

I know that the ...props is passing maxWidth to Grid component (and it's a html element), but I'm confusing about how to use it without these console log's

Upvotes: 2

Views: 2495

Answers (3)

joshwilsonvu
joshwilsonvu

Reputation: 2679

Let's separate exactly which props are used for styling and which props are sent to the Grid component. Using rest, we can "pull out" certain properties from the props object and send the rest to the Grid component. Then, the properties that we pull out will form the CSS.

import React from 'react'
import Grid from '@material-ui/core/Grid'

import { spacing, sizing, color, flexbox, display } from '@material-ui/system'
import styled from 'styled-components'


const Row = styled(
  ({ maxWidth, somethingElse, ...rest }) => <Grid container {...rest} />
)`
  ${spacing}
  maxWidth: ${props => props.maxWidth || defaultValue1};
  somethingElse: ${props => props.somethingElse || defaultValue2};
`;

export default Row

Upvotes: 1

tanks a lot about the anwsors. Based in these answers, I develop a helper to separate this kind of props:

import React from 'react'
import styled from "styled-components";
import Button from "@material-ui/core/Button";
import { spacing, sizing } from "@material-ui/system";

const allowedProps = ({props, system}) => {
    const notAllowedProps = filterProps({props, system})
    const allowedProps = Object.entries(props).reduce((acc, [key, value]) => {
        if (!notAllowedProps.includes(key)) {
            return {...acc, [key]: value}
        }
        return acc
    }, {})
    return allowedProps
}

const filterProps = ({props, system}) => {
    const objSystem = system.reduce((acc, element) => ({
        ...acc,
        ...element(props)
    }), {})
    return Object.keys(objSystem)
}

const ButtonBase = (props) => <Button {...allowedProps({props, system: [spacing, sizing]})} />

const MyButton = styled(ButtonBase)...

Upvotes: 0

Nick Kinlen
Nick Kinlen

Reputation: 1406

The Material-UI documentation shows examples of various approaches to styling, including an example showing how to use styled-components with Material-UI.

Here is the example they show:

import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const MyButton = styled(Button)({
  background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
  border: 0,
  borderRadius: 3,
  boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
  color: 'white',
  height: 48,
  padding: '0 30px',
});

export default function StyledComponents() {
  return <MyButton>Styled Components</MyButton>;
}

Another approach is using the Material-UI hook that uses a CSS-in-JS approach and the makeStyles function:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  },
});

export default function Hook() {
  const classes = useStyles();
  return <Button className={classes.root}>Hook</Button>;
}

There's also a way to create a custom theme in a separate file and import it where it's needed. Here is an example of the default Theme object and what it contains. It's good to take a look at and get an idea of what can be customized by using createMuiTheme.

Material-UI has multiple approaches to styling and it can be a lot to take in at first. Hope this helps.

Upvotes: 0

Related Questions