Skip to content

Commit 07564e3

Browse files
committed
fix: forward as prop when wrapping another styled component
Say you have 2 components like this: ```js const First = styled.a`color: blue;`; const Second = styled(First)`font-size: 14px;`; <Second as="button" /> ``` Previously this would render a `button` with the style `font-size: 14px;`, because the `First` component is swapped for `button`. This commit changes the behaviour so that if the wrapped tag is a styled component, it'll forward the `as` prop. Which means the resulting styles will now be `color: blue; font-size: 14px;`. It also matches the behaviour of the styled-components library.
1 parent d7629e2 commit 07564e3

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

src/__tests__/__snapshots__/styled.test.js.snap

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ exports[`applies CSS variables in style prop 1`] = `
1616
</div>
1717
`;
1818

19+
exports[`forwards as prop when wrapping another styled component 1`] = `
20+
<a
21+
className="hijklmn abcdefg"
22+
>
23+
This is a test
24+
</a>
25+
`;
26+
1927
exports[`handles wrapping another styled component 1`] = `
2028
<div
2129
className="hijklmn abcdefg"
@@ -24,6 +32,20 @@ exports[`handles wrapping another styled component 1`] = `
2432
</div>
2533
`;
2634

35+
exports[`merges CSS variables with custom style prop 1`] = `
36+
<div
37+
className="abcdefg"
38+
style={
39+
Object {
40+
"--foo": "tomato",
41+
"bar": "baz",
42+
}
43+
}
44+
>
45+
This is a test
46+
</div>
47+
`;
48+
2749
exports[`renders component with display name and class name 1`] = `
2850
<div
2951
className="abcdefg"
@@ -40,6 +62,14 @@ exports[`renders tag with display name and class name 1`] = `
4062
</h1>
4163
`;
4264

65+
exports[`replaces custom component with as prop 1`] = `
66+
<a
67+
className="abcdefg"
68+
>
69+
This is a test
70+
</a>
71+
`;
72+
4373
exports[`replaces simple component with as prop 1`] = `
4474
<a
4575
className="abcdefg"

src/__tests__/styled.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ it('applies CSS variables in style prop', () => {
5252
expect(tree.toJSON()).toMatchSnapshot();
5353
});
5454

55+
it('merges CSS variables with custom style prop', () => {
56+
const Test = styled('div')({
57+
name: 'TestComponent',
58+
class: 'abcdefg',
59+
vars: {
60+
foo: ['tomato'],
61+
},
62+
});
63+
64+
const tree = renderer.create(
65+
<Test style={{ bar: 'baz' }}>This is a test</Test>
66+
);
67+
68+
expect(tree.toJSON()).toMatchSnapshot();
69+
});
70+
5571
it('supports extra className prop', () => {
5672
const Test = styled('div')({
5773
name: 'TestComponent',
@@ -85,6 +101,19 @@ it('replaces simple component with as prop', () => {
85101
expect(tree.toJSON()).toMatchSnapshot();
86102
});
87103

104+
it('replaces custom component with as prop', () => {
105+
const Custom = props => <div {...props} style={{ fontSize: 12 }} />;
106+
107+
const Test = styled(Custom)({
108+
name: 'TestComponent',
109+
class: 'abcdefg',
110+
});
111+
112+
const tree = renderer.create(<Test as="a">This is a test</Test>);
113+
114+
expect(tree.toJSON()).toMatchSnapshot();
115+
});
116+
88117
it('handles wrapping another styled component', () => {
89118
const First = styled('div')({
90119
name: 'FirstComponent',
@@ -101,6 +130,22 @@ it('handles wrapping another styled component', () => {
101130
expect(tree.toJSON()).toMatchSnapshot();
102131
});
103132

133+
it('forwards as prop when wrapping another styled component', () => {
134+
const First = styled('div')({
135+
name: 'FirstComponent',
136+
class: 'abcdefg',
137+
});
138+
139+
const Second = styled(First)({
140+
name: 'SecondComponent',
141+
class: 'hijklmn',
142+
});
143+
144+
const tree = renderer.create(<Second as="a">This is a test</Second>);
145+
146+
expect(tree.toJSON()).toMatchSnapshot();
147+
});
148+
104149
it('throws when using as tag for template literal', () => {
105150
expect(
106151
() =>

src/react/styled.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ function styled(tag /* : React.ComponentType<*> | string */) {
4444
rest.style = Object.assign(style, rest.style);
4545
}
4646

47+
/* $FlowFixMe */
48+
if (typeof tag.className === 'string' && tag !== component) {
49+
// If the underlying tag is a styled component, forward the `as` prop
50+
// Otherwise the styles from the underlying component will be ignored
51+
return React.createElement(
52+
tag,
53+
Object.assign(rest, {
54+
as: component,
55+
})
56+
);
57+
}
58+
4759
return React.createElement(component, rest);
4860
});
4961

0 commit comments

Comments
 (0)