Skip to content

Commit

Permalink
[system] Don't spread props to DOM for string tags (#33761)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp committed Aug 4, 2022
1 parent e4172c5 commit 1dca946
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
14 changes: 14 additions & 0 deletions packages/mui-system/src/createStyled.js
Expand Up @@ -8,6 +8,17 @@ function isEmpty(obj) {
return Object.keys(obj).length === 0;
}

// https://github.com/emotion-js/emotion/blob/26ded6109fcd8ca9875cc2ce4564fee678a3f3c5/packages/styled/src/utils.js#L40
function isStringTag(tag) {
return (
typeof tag === 'string' &&
// 96 is one less than the char code
// for "a" so this is checking that
// it's a lowercase character
tag.charCodeAt(0) > 96
);
}

const getStyleOverrides = (name, theme) => {
if (theme.components && theme.components[name] && theme.components[name].styleOverrides) {
return theme.components[name].styleOverrides;
Expand Down Expand Up @@ -104,6 +115,9 @@ export default function createStyled(input = {}) {
} else if (componentSlot) {
// any other slot specified
shouldForwardPropOption = slotShouldForwardProp;
} else if (isStringTag(tag)) {
// for string (html) tag, preserve the behavior in emotion & styled-components.
shouldForwardPropOption = undefined;
}

const defaultStyledResolver = styledEngineStyled(tag, {
Expand Down
53 changes: 53 additions & 0 deletions packages/mui-system/src/createStyled.test.js
Expand Up @@ -281,4 +281,57 @@ describe('createStyled', () => {
});
});
});

it('does not spread `sx` prop to DOM', () => {
const styled = createStyled({});
const Button = styled('button')({});

const { container } = render(<Button sx={{ bgcolor: 'red' }}>Link</Button>);
expect(container.firstChild).not.to.have.attribute('sx');
});

it('does not forward `ownerState` prop to DOM', () => {
const styled = createStyled({});
const Button = styled('button')({});

const { container } = render(<Button ownerState={{}} />);
expect(container.firstChild).not.to.have.attribute('ownerState');
});

describe('default behaviors', () => {
it('does not forward invalid props to DOM if no `slot` specified', () => {
// This scenario is usually used by library consumers
const styled = createStyled({});
const Button = styled('button')({});

const { container } = render(
<Button color="red" shouldBeRemoved data-foo="bar">
Link
</Button>,
);
expect(container.firstChild.getAttribute('data-foo')).to.equal('bar');
expect(container.firstChild.getAttribute('color')).to.equal('red'); // color is for Safari mask-icon link
expect(container.firstChild.getAttribute('shouldBeRemoved')).not.to.equal('true');
});

it('can use `as` prop', () => {
const styled = createStyled({});
const Button = styled('button')({});

const { container } = render(<Button as="a" href="/" />);

expect(container.firstChild).to.have.tagName('a');
expect(container.firstChild).to.have.attribute('href', '/');
});

it('able to pass props to `as` styled component', () => {
const styled = createStyled({});
const ChildRoot = styled('div')({});
const Child = ({ component }) => <ChildRoot as={component}>content</ChildRoot>;
const Button = styled('button')({});
const { container } = render(<Button as={Child} component="span" />);

expect(container.firstChild).to.have.tagName('span');
});
});
});

0 comments on commit 1dca946

Please sign in to comment.