Let's try to recreate the button we build with SASS, but through using our new tool. We won't try to mimic the SASS code, but we'll try to apply some of the same concepts like defining constants in a separate file, having functions work as mixins, and extending a class as we did earlier. We have a problem, because styled-components doesn't provide color functions as SASS does, so we'll add a new library to take care of that, color:
npm install color --save
Now, we are set. First, we'll have some basic color constants, in file constants.js, that could be used everywhere:
export const NORMAL_COLOR = "green";
export const NORMAL_TEXT = "yellow";
export const ALERT_COLOR = "red";
export const ALERT_TEXT = "white";
Now we'll directly get to defining our component, since all styling will also be there. First, we'll need some imports:
// Source file: /src/components/styledButton/styledButton.js
/* @flow */
import React from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import Color from "color";
import {
NORMAL_TEXT,
NORMAL_COLOR,
ALERT_TEXT,
ALERT_COLOR
} from "./constants";
// continues...
Given this, we can get to the main code. We'll have a makeSpan() function that will work as a mixin; we'll get to use it very shortly, and we'll see what props means:
// ...continued
const makeSpan = props => `
span {
color: ${props.normal ? NORMAL_TEXT : ALERT_TEXT};
font-weight: bold;
}
`;
// continues...
Then, we'll define a BasicStyledDiv component, with some basic styling, that will do as a base class for our button. (Remember, we are working in this unneedlessly complex way, just to highlight several features you may want to use in problems that really need it!) This component will roughly be the equivalent of our %baseButton declaration in SASS, from the previous section:
// ...continued
const BasicStyledDiv = styled.div`
display: inline-block;
text-decoration: none;
padding: 5px 10px;
border-radius: 3px;
`;
// continues...
After, we can create a StyledDiv component by extending the previous one. Since styled-component lets us use functions and expressions, we won't have to create two distinct styles, as we did with SASS when we built .normalButton and .alertButton. Also, note that we can use & here, meaning a reference to the class, just as in SASS:
// ...continued
const StyledDiv = BasicStyledDiv.extend`
background-color: ${props =>
props.normal ? NORMAL_COLOR : ALERT_COLOR};
&:hover {
background-color: ${props =>
Color(props.normal ? NORMAL_COLOR : ALERT_COLOR)
.darken(0.25)
.string()};
transition: all 0.5s ease;
}
${props => makeSpan(props)};
`;
// continues...
What is this props parameter we see? When creating a style, the component's props will be passed to our code, so we can tweak our style. In this case, if the component's this.props.normal value is true, NORMAL_COLOR will be used; otherwise, ALERT_COLOR will apply. This simplifies our code a lot, because we won't have to create styles in a fixed fashion; we can make them adjust to whatever we want.
After all of this, the code for our button itself is very simple:
// ...continued
export class StyledButton extends React.PureComponent<{
normal: boolean,
buttonText: string,
onSelect: void => void
}> {
static propTypes = {
normal: PropTypes.bool.isRequired,
buttonText: PropTypes.string.isRequired,
onSelect: PropTypes.func.isRequired
};
render() {
return (
<StyledDiv
normal={this.props.normal}
onClick={this.props.onSelect}
>
<span>{this.props.buttonText}</span>
</StyledDiv>
);
}
}
// continues...
Writing a story to check this is actually trivial, because we only need to copy the previous one we wrote for the SASS style button and substitute StyledButton for SassButton; no need for anything else. (OK, I also changed some strings for clarity, but those edits are trivial.) If we launch Storybook, we can quickly verify that our new button works in the same way as our previous one; see following screenshot for evidence of that: