DEV Community

André Castelo
André Castelo

Posted on

Prop forwarding with Emotion, Material-UI and Material-UI-system

Material-ui-system is an awesome library, but when using with @emotion/styled there might be a few annoying warnings, complaining that you're passing an invalid property to a DOM node. Here's a quick function to prevent that:

import memoize from '@emotion/memoize';
import isPropValid from '@emotion/is-prop-valid';
/**
* These props will not be forwarded to the wrapped element by @emotion/styled.
*/
// prettier-ignore
const props: string[] = [
// @material-ui/system/borders
'border', 'borderBottom', 'borderColor', 'borderLeft', 'borderRadius',
'borderRight', 'borderTop',
// @material-ui/system/shadows
'boxShadow',
// @material-ui/system/spacing
'm', 'mx', 'my', 'margin',
'mb', 'marginBottom',
'ml', 'marginLeft',
'mr', 'marginRight',
'mt', 'marginTop',
'p', 'px', 'py', 'padding',
'pb', 'paddingBottom',
'pl', 'paddingLeft',
'pr', 'paddingRight',
'pt', 'paddingTop',
// @material-ui/system/display
'displayPrint', 'display',
// @material-ui/system/flexbox
'alignContent', 'alignItems', 'alignSelf', 'flex', 'flexDirection',
'flexGrow', 'flexShrink', 'flexWrap', 'justifyContent', 'order',
// @material-ui/system/palette
'bgColor', 'color',
// @material-ui/system/positions
'bottom', 'left', 'position', 'right', 'top', 'zIndex',
// @material-ui/system/sizing
'height', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'width', 'boxSizing',
// @material-ui/system/typography
'fontFamily', 'fontSize', 'fontWeight', 'textAlign',
];
const regex = new RegExp(`^(${props.join('|')})$`);
type Fn<T> = (key: string) => T;
/**
* The return function will only filter out the props listed above. This is the
* one we want to use if we are wrapping a Material-UI component.
*/
export const createShouldForwardProp = (): Fn<boolean> =>
memoize((prop) => !regex.test(prop));
export default createShouldForwardProp();
/**
* The created function will filter out the props listed above and any prop
* that is not a valid DOM prop. So this is the function we want to use if
* we are wrapping existing DOM components.
*/
const createShouldForwardDomProp = (): Fn<boolean> =>
memoize((prop) => isPropValid(prop) && !regex.test(prop));
export const shouldForwardDomProp: Fn<boolean> = createShouldForwardDomProp();

And an example overriding an existing Material-UI component:

import styled from '@emotion/styled';
import {
Typography as MaterialTypography,
TypographyProps as MaterialTypographyProps,
} from '@material-ui/core';
import {
spacing,
SpacingProps,
sizing,
SizingProps,
typography,
TypographyProps as MaterialSystemTypographyProps,
} from '@material-ui/system';
import shouldForwardProp from './shouldForwardProp';
type TypographyProps = MaterialTypographyProps &
SpacingProps &
SizingProps &
MaterialSystemTypographyProps;
export const Typography = styled(MaterialTypography, {
shouldForwardProp,
})<TypographyProps>`
${sizing}
${spacing}
${typography}
`;

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay