Reputation: 2733
If I want a button but, only the presentational part of that, so if I do:
import styled from 'styled-components'
const Button = styled.button`
color: red;
text-align: center;
`
I'm forced to render a button
tag, but what about if semantically I need an anchor?
Upvotes: 22
Views: 17968
Reputation: 34367
Use the "as" polymorphic prop in v4
copy/pasta from the example in the docs:
const Component = styled.div`
color: red;
`;
render(
<Component
as="button"
onClick={() => alert('It works!')}
>
Hello World!
</Component>
)
Upvotes: 37
Reputation: 31
As @typeoneerror pointed out, styled-components provides WithComponent
. You can use this to to create a new component based on a prop containing the tag. Piggybacking off the example, it would look like this:
const _Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const Button = ({ as: tag = 'button', children, ...props }) => {
// We're replacing the <button> tag with whatever tag is assigned to the 'as' prop (renamed to 'tag' and defaulted to button), but reuse all the same styles
const Composed = _Button.withComponent(tag);
// We return the newly-created component with all its props and children
return <Composed {...props}>{children}</Composed>;
};
render(
<div>
<Button>Normal Button</Button>
<Button as='a'>Normal Link</Button>
</div>
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Upvotes: 3
Reputation: 56948
styled-components provides withComponent
that'll be useful for cases where you want to use an a different tag with a component. This is similar to @siddharthkp's answer in function, but uses the API.
Example from the documentation:
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// We're replacing the <button> tag with an <a> tag, but reuse all the same styles
const Link = Button.withComponent('a')
// Use .withComponent together with .extend to both change the tag and use additional styles
const TomatoLink = Link.extend`
color: tomato;
border-color: tomato;
`;
render(
<div>
<Button>Normal Button</Button>
<Link>Normal Link</Link>
<TomatoLink>Tomato Link</TomatoLink>
</div>
);
Upvotes: 11
Reputation: 2733
I've asked the same question on styled-components issue tracker: https://github.com/styled-components/styled-components/issues/494
And the current "solution" that I've found is:
// agnosticStyled.js
import React from 'react'
import styled from 'styled-components'
export default styled(
({tag = 'div', children, ...props}) =>
React.createElement(tag, props, children)
)
And then when you need it:
import React from 'react'
import styled from './agnosticStyled'
const Button = styled`
color: palevioletred;
text-transform: uppercase;
`
export default Button
And finally:
import React from 'react'
import Button from './Button'
const Component = () =>
<div>
<Button>button</Button>
<Button tag="button">button</Button>
<Button tag="a" href="https://google.com">button</Button>
</div>
export default Component
Here a full functioning example: https://codesandbox.io/s/6881pjMLQ
Upvotes: 6
Reputation: 71
You can use it with a anchor tag as well, there's nothing stopping you.
import styled from 'styled-components'
const Button = styled.a`
color: red;
text-align: center;
`
If you want to keep both, you can reuse the styles by pulling them out:
import styled from 'styled-components'
const styles = `
color: red;
text-align: center;
`
const Button = styled.button`
${styles}
`
const LinkButton = styled.a`
${styles}
`
Upvotes: 7
Reputation: 19967
Since we're just using JavaScript, why not use a function?
const myButtonStyle = (styled, tag) => {
return styled[tag]`
color: red;
text-align: center;
`
}
const Button = myButtonStyle(styled, 'button')
Upvotes: 2