This content originally appeared on DEV Community and was authored by _CODE
Hello, everybody! ?
And welcome to the 3rd lecture of the Styled Components 101 series ?
In this lecture, we'll be covering:
1️⃣ How we can use Styled Components within a Next.js configuration.
2️⃣ How to use custom icon fonts within our styled components.
If you're new to Styled Components and this lecture is the first one you run into, I suggest taking a look at the previous lectures first, where we covered some basic concepts and examples of Styled Components.
With all this said, let's move on to today's topic ?
How to get Styled Components to work if we're using Next.js ?
Let's first see what happens if no configuration for Styled Components has been defined for our Next.js project and we try to use the library.
To start off, we're going to create a StyledButton
component (already known to all at this point ?) and render it within the main component of our app.
StyledButton.js
import styled from "styled-components";
export default styled.button`
background-color: ${props => props.bg};
color: ${props => props.color};
border: none;
border-radius: 5px;
padding: 20px;
font-size: 1.5rem;
`
index.js
import StyledButton from '../components/StyledButton';
const Home = () => {
return(
<StyledButton bg="#c64dff" color="#fff">Styled Button in Next.js</StyledButton>
)
}
If we run our app, this is the resultant button:
Where in the world are our styles? ? Let's find out what's going on in here.
First, if we go to the Console Tab in the browser's dev tools, we see that something is throwing an error:
The error reads:
_Warning: Prop `classname` did not match. Server: "sc-pNWdM kcTaxf" Client: "sc-bdnxRM gSuzZs" at button...
It seems like two different classes are being assigned on the server and the client, resulting in an inconsistency.
Let's now have a look at the Elements tab:
Our button is there and we can confirm that the class provided by Styled Components has been assigned correctly, but the styles are completely missing.
So, what can we do to solve this? ?
Well, this is neither a bug nor even a big deal. It's just that a further configuration is required by Next.js to get to work Styled Components in our project in order to use it.
So, first, we're going to install the babel-plugin-styled-components
, which is required for SSR (Server Side Rendering).
npm install babel-plugin-styled-components
Now, let's create a .babelrc
file if we haven't already done so (it's not created by default when creating a Next.js app) and write the following configuration for the newly installed plugin on it:
On the terminal:
touch .babelrc
.babelrc
{
"presets": ["next/babel"],
"plugins": [["styled-components", {"ssr": true, "preprocess": false}]]
}
But we're not done yet, we still need a little bit more of configuration.
Now we need to inject the server side rendered styles in the <head>
element of our HTML file. For this purpose, we need to override the Document file, which is provided by Next.js.
The Document file is extendable, which means that we can add content to it if needed, and it's mainly used to add custom content to the <html>
and <body>
elements of the HTML main file. Note that this file is only rendered on the server.
This document is automatically generated with the creation of the Next.js app, but since we need to extend it, we're going to create another file called _document.js
to override the original one. This new file should be placed within the /pages
directory and it will look like this ?
_document.js
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
Note that renderPage
should only be modified when working with CSS-in-JS libraries, like Styled Components, since they need the app to be wrapped to work on server side. Otherwise the default configuration should always remain ?
If we're not planning to use any of these libraries, the following configuration could be a good starting point if we need to add something to the structure of our HTML document, being able to remove all that we don't need to change (note that we're overriding), like getInitialProps
or even the render
method:
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
In any other case, there's no need to extend the original Document and we can forget about it ?.
Once we've made all of these arrangements, let's re-run our application and see what happens!
There we go! Our Styled Button is finally rendering properly ?
And that would be all the configuration needed to work with Styled Components + Next.js.
Let's now dive into how we can add a custom icon font to a styled component ?
Custom Icon Fonts in Styled Components ❤️
This topic is totally separate from the previous one, since an extra configuration for fonts is no longer required in Next.js, but anyway, let's extend our styled button by adding an icon from a custom icon font and let's see what we need to do to make it work.
First of all... What is an icon font? ?
Unlike regular fonts, which contain letters and numbers, an icon font is nothing more than a collection of symbols and glyphs that works as a typeface. Its use is widely extended because they are really easy to style with CSS.
The tool we're going to use to get our icon font is Icomoon, but this example works for every downloaded fonts coming from any font resource.
Let's say we have already downloaded our font files after generating the custom set and we're all set and ready to go.
Integrating a custom icon font set into our project ?
What we're going to do in this section is to add an icon from our custom icon font as an ::after
pseudo-element, to place it after the text of our button.
So, first, we're going to add a new prop to our styled button call and pass it the content value of an icon of our choice.
Note that every icon has a sort of id, which is the value we'll pass in to the prop named icon. This content value is always provided by the tool, so you don't need to assign it yourself.
In this case, the content value for our icon is \e900
.
<StyledButton bg="#c64dff" color="#fff" icon="\e900">Styled Button in Next.js</StyledButton>
Then, we'll just add the ::after
pseudo-element to the StyledButton definition:
import styled from "styled-components";
export default styled.button`
background-color: ${props => props.bg};
color: ${props => props.color};
border: none;
border-radius: 5px;
padding: 20px;
font-size: 1.2rem;
&::after{
font-family: "icomoon";
content: "${props => props.icon}";
padding-left: 8px;
}
`
Time to create a global style ⚡️
In the previous lecture, we had a glimpse on how to create a global style, as part of the example where we created a light/ dark theme toggler. So don't hesitate to take a look at it for further reference if needed ?
But in case you missed it or you don't have the time to read one more article, keep reading: everything's explained ahead ✌️
First, we are going to create our global styles file, that will be called IconFont.js
, and which will host the CSS definition to import custom fonts. It's just plain CSS inside a styled component. Nothing new ? And it will look like this:
IconFont.js
import { createGlobalStyle } from "styled-components";
export default createGlobalStyle`
@font-face {
font-family: "icomoon";
src: url("/fonts/icomoon.eot");
src: url("/fonts/icomoon.eot?#iefix")
format("embedded-opentype"),
url("/fonts/icomoon.svg#icomoon") format("svg"),
url("/fonts/icomoon.woff") format("woff"),
url("/fonts/icomoon.ttf") format("truetype");
};
`
Things to consider at this point
Pay attention to the routes and the filenames: the ones you're seeing above work for the configuration that we're going to see in a minute. You should always use the actual routes of your project and the names you provided to your font files. Otherwise, it won't work ❌
It may sound obvious but sometimes it happens that we make a mistake in writing this definition and we go nuts for the rest of the day trying to figure out what's going on. Believe me, it happens more often that you may think ?In case you're using a theme, you're supposed to already have a global styles file. In such case, just add the
@font-face
definition to it and you'd be set and done.
Then, how do I have to structure my project to make the previous @font-face
definition work?
First, and as mentioned before, you need to use the actual names of your font files and define every possible format you have for that font (you will likely have something like .ttf, .otf, .svg, and/or .woff, but there are others, too).
And, second, and key to this configuration ? You need to create a fonts
directory inside the /public
directory.
This is necessary because Next.js serves static files under the /public
folder, so since fonts are a static resource, they have to be located in there.
Note that every resource placed in the
/public
directory should be routed using a slash/
before its name.
Making our global theme accessible by the app
As a final step to be able to start using our custom icon font, we just need to import the IconFont
component into our main app component, _app.js
, like this:
_app.jsx
import IconFont from '../components/IconFont';
const MyApp = ({ Component, pageProps }) => {
return (
<>
<IconFont />
<Component {...pageProps} />
</>)
}
export default MyApp;
If everything goes as expected, this will be the result of our styled button, to which we have appended a heart icon:
Otherwise, if something went wrong along the way, this is what we'll see:
Getting a square instead of the actual icon can mean:
- The icon font has been found but the value for the content you have provided is not part of the list of values of that font.
- There's a problem with the location of the fonts: the specified font files are not located at the route you have provided.
- Something wasn't configured properly.
Older versions of Next.js
As of Next.js 11, no extra configuration for Webpack is required to translate font file formats. If you're using an older version, it's highly recommended that you update your package version by running the following command:
npm install next@latest
In case you need to use an outdated version for whatever reasons, keep in mind that a little bit of further configuration will be required: you'll need to install the file-loader
Webpack loader, which will handle font formats appropriately and bundle them up to include them in the final bundle that will be served to the browser, and then, you'll have to add the corresponding configuration in next.config.js
.
And this is all for the third Styled Components 101 lecture!
Stay tuned to know more about Styled Component in future episodes of the series.
A big thanks for reading ? and don't hesitate to reach out to me if you any questions or doubts about today's lecture.
I hope you found this article useful and I see you all in the next ?
? Don't forget to follow @underscorecode on Instagram and Twitter for more daily webdev content ??
And last but not least... A quick friendly reminder before we go ?
We all know there are million ways to get things done when it comes to programming and development, and we're here to help and learn, so, if you know another possible way to do what others are sharing (not better, not worse, just different), feel free to share it if you feel like it, but, please, always be kind and respectful with the author and the rest of the community. Thank you and happy coding!
This content originally appeared on DEV Community and was authored by _CODE
_CODE | Sciencx (2021-08-08T14:09:13+00:00) Styled Components 101 ? Lecture 3: SSR with Next.js + Custom Icon Fonts ?. Retrieved from https://www.scien.cx/2021/08/08/styled-components-101-%f0%9f%92%85-lecture-3-ssr-with-next-js-custom-icon-fonts-%f0%9f%98%8d/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.