May 25, 2020
When learning styled components, you may have noticed the use of attrs
and be thinking:
Huh. What does this do? When would I need to use attrs
?
The best way to explain the use case of attrs()
in styled components is to dive right into some examples.
Ready? Let’s do it.
Here I’ve put together a simple button styled component:
import styled from 'styled-components';const Button = styled.button`display: block;font-size: 1rem;font-weight: bold;color: white;border-radius: 4px;transition: 0.2s;cursor: pointer;border: none;padding: 1rem;&:hover {opacity: 0.7;}`export { Button };
And I’m going to use a couple of these styled button components in my app:
import React from 'react';import { Button } from 'components/common';const App = () => {return (<><h1>Buttons</h1><Button>Hello there</Button><Button>Wassuuuupppp</Button><Button>Click me</Button></>)}export default App;
In case you didn’t know, the default type for HTML buttons is type="submit"
.
So in my above design, when a button is clicked it will result in a page reload (because of the default behavior).
But what if you wanted to change the default type to type="button"
?
Or set any HTML attribute as default for that matter?
Well, you could add this as a prop directly to the component like this:
import React from 'react';import { Button } from 'components/common';const App = () => {return (<><h1>Buttons</h1><Button type="button">Hello there</Button><Button type="button">Wassuuuupppp</Button><Button type="button">Click me</Button></>)}export default App;
However, if the attribute can be considered a default across your application, it’s better to use the attrs()
function instead and define the default there:
import styled from 'styled-components';const Button = styled.button.attrs(props => ({type: props.type || 'button'// Every <Button /> will now have type="button" as default}))`display: block;font-size: 1rem;font-weight: bold;color: white;border-radius: 4px;transition: 0.2s;cursor: pointer;border: none;padding: 1rem;&:hover {opacity: 0.7;}`export { Button };
This is much more efficient than adding a prop to every component if you find yourself turning to the same attribute over and over.
Or put another way:
The rule of thumb is to use
attrs
when you want every instance of a styled component to have that prop, and pass props directly when every instance needs a different one -Styled Components Docs
This means that we can omit the default attribute, and only pass props when we want to change the default:
import React from 'react';import { Button } from 'components/common';const App = () => {return (<><h1>Buttons</h1><Button>Hello there</Button><Button>Wassuuuupppp</Button>// Add a prop to override the default defined in attr<Button type="submit">Click me</Button></>)}
That is the simplest way to get started with attrs
!
If you’re looking to get more dynamic continue on to the next use case…
Building from the previous use case, using attrs
also allows you to attach dynamic props to a component.
Sticking with our button example from use case 1, let’s add a default size of our button:
import styled from 'styled-components';const Button = styled.button.attrs(props => ({type: props.type || 'button'}))`display: block;font-size: 1rem;font-weight: bold;color: white;border-radius: 4px;transition: 0.2s;cursor: pointer;border: none;/* define default margin and padding: */margin: 1rem;padding: 1rem;&:hover {opacity: 0.7;}`export { Button };
The above code will make the margin and padding for all buttons 1rem
by default.
We can, however, make this more dynamic.
Let’s say we want to make a larger version of the button, we could pass a size prop like this:
const App = () => {return (<><h1>Buttons</h1><Button size="2rem">Hello there</Button><Button size="3rem">Wassuuuupppp</Button>// Add a prop to override the default defined in attr<Button type="submit">Click me</Button></>)}
And then in our styled component, we can make the margin and padding dynamic:
import styled from 'styled-components';const Button = styled.button.attrs(props => ({type: props.type || 'button',size: props.size || '1rem'}))`display: block;font-size: 1rem;font-weight: bold;color: white;border-radius: 4px;transition: 0.2s;cursor: pointer;border: none;/* pass the dynamic props: */margin: ${props => props.size};padding: ${props => props.size};&:hover {opacity: 0.7;}`export { Button };
This leverages what we learned in use case 1:
We set the default size as 1rem
, but if a specific prop is passed, it overwrites the default.
With this override, we can now dynamically set the margin and padding using the passed prop.
In short, the use case of attrs()
in styled components is:
Levelling up your React and CSS skills in 2021 is a great idea. Here's why: