Introduction
Lately, I've been playing with styled-components. It is a CSS-in-JS library that uses tagged template literals. I want to talk about three concepts that I got puzzled by: Interpolation
, GlobalStyle
and ThemeProvider
.
What is Interpolation?
Interpolation is adapting a component based on the props passed to it; meaning, you can inject values through props. For example:
const MockElement = styled.div`
--size: ${(props) => (props.big ? '100px' : '50px')};
width: var(--size);
height: var(--size);
background-color: yellowgreen;
`;
render(
<div>
// This renders a 50x50 square, because there was no "big" prop
<MockElement />
// This renders a 100x100 square, because "big" was passed
<MockElement big />
<div>
)
So you can use props as truthy values. What about custom values? That works too!
const MockElement = styled.div`
background-color: ${props => props.color ? props.color : 'yellowgreen'};
--size: ${(props) => (props.big ? '100px' : '50px')};
width: var(--size);
height: var(--size);
`;
render(
<div>
// This renders a blue square
<MockElement color='blue'/>
// This renders... no color??
<MockElement color />
<div>
)
Styled props are truthy by default, but since no value was passed, nothing gets rendered. To use the default value with this technique, you either skip the prop entirely, or you pass a null
.
But BEWARE! You must pass a function when interpolating a value, or the code breaks. Something like the following wouldn't work:
const MockElement = styled.div`
background-color: ${props.color}; /* It must be a function */
`;
Must the function be inline? No! You can simply pass any function as a callback:
function declaredFunction (props) {
let scale = `${props.factor * 50}px`
return scale
}
const MockElement = styled.div`
--size: ${declaredFunction};
width: var(--size);
height: var(--size);
background-color: ${props => props.color ? props.color : 'yellowgreen'};
`;
render(
<div>
// This renders a 150x150, yellowgreen square
<MockElement big color={null} factor={3}/>
<div>
)
This marks the end of exploring interpolation
. On to the next!
What is GlobalStyle?
Self-explanatory as the name is, a GlobalStyle component is used to define general styling rules for the application. A close comparison would be using an index.css
file that gets imported and bundled before all other stylesheets, thus being overwritten by css modules that follow it later.
Using a global style is fairly simple! First, you must create the GlobalStyle.js
file, like so:
import { createGlobalStyle } from 'style-components';
const GlobalStyle = createGlobalStyle`
/* Insert global styling here */
`;
export default GlobalStyle;
Then, put the component...anywhere, really. At least, in the few tests I did, I put the component anywhere within the project and it worked just fine. However, for the sake of organization, I've put in my routing system (with react-router), like so:
# App.js
import GlobalStyle from './utils/GlobalStyle';
function App() {
return (
<BrowserRouter>
<GlobalStyle />
<Routes>
{/*The routes and elements go here*/}
</Routes>
</BrowserRouter>
);
}
Cool! On to the final topic: ThemeProvider
.
What is ThemeProvider?
ThemeProvider is a source of universal props to all its children. You must put the component at the root of your project, if you want all components to have access to it.
So, if you use App.js
as your root, you could do something like:
#App.js
import { ThemeProvider } from 'styled-components';
const themeObject = {
button : {
primary : {
background: 'lightblue',
color: 'white',
},
secondary: {
/* other keywords*/
}
}
}
function App() {
return (
<ThemeProvider theme={themeObject}>
<CoolButton />
</ThemeProvider>
);
}
That themeObject
becomes accessible to all objects that are children of ThemeProvider
. You use the theme
prop through interpolation
, like this:
#CoolButton.styled.js
import styled from 'styled-components';
const CoolButton = styled.button`
background-color: ${props => props.theme.button.primary.background};
/* As seen above and below, you just need to access the string from the theme object */
color: ${props => props.theme.button.primary.color};
`
You can also combine all three components, by making GlobalComponent
a child of ThemeProvider
and interpolating values as needed. One useful example is setting the font family.
# theme.js
const theme = {
heading: "Cool Heading",
subHeading: "Cute Heading"
};
export default theme;
# GlobalStyle.js
import { createGlobalStyle } from 'styled-components';
import coolFontPath from './font-file1.woff';
import cuteFontPath from './font-file2.woff';
const GlobalStyle = createGlobalStyle`
@font-face {
font-family: 'Cool Heading';
src: url(${coolFontPath};
}
@font-face {
font-family: 'Cute Heading';
src: url(${cuteFontPath};
}
h1 {
font-family: ${props => props.theme.heading};
}
span.subheading {
font-family: ${props => props.theme.subHeading}
}
`
export default GlobalStyle;
# App.js
import GlobalStyle from './GlobalStyle.js';
import theme from './theme.js';
import { ThemeProvider } from 'styled-components';
const App = () => {
return (
<ThemeProvider theme={theme}>
<h1>I belong to the Cool Heading family</h1>
<span className='subheading'>
I belong to the Cute Heading family
</span>
</ThemeProvider>
);
}
Summary
So there you have it! This was the exploration of three important concepts of the styled-library: Interpolation
, GlobalStyling
and ThemeProvider
. Hope it was of use!
Top comments (0)