13.2 Styling and Themeing
# Tailwind
For a basic introduction to Tailwind, please refer back to the notes in MAD9013 (opens new window).
Tailwind is the current best practice for NextJS. The other styling approaches in this module are good for React SPAs.
The notes on this page will specifically connect Tailwind with React and NextJS.
Here is the NextJS reference to using Tailwind with NextJS (opens new window)
When you use npx create-react-app@latest you will be prompted about wanting to use Tailwind. If you say yes then you can skip these set up steps. If you have an existing project that doesn't have
Tailwind already then you can follow these instructions to add it to your project.
To add Tailwind for your NextJS web app, run the npm commands in the terminal to generate both the tailwind.config.js and postcss.config.js files.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
2
Once these files have been created, you will need to update the contents of the tailwind.config.js file with the names of files that will be using tailwind.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}', // Note the addition of the `app` directory.
'./pages/**/*.{js,ts,jsx,tsx,mdx}', //for older versions of NextJS that use page instead of app router
'./components/**/*.{js,ts,jsx,tsx,mdx}',
// Or if using `src` directory:
'./src/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {},
},
plugins: [],
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Next, you should update the top of your globals.css file inside /app/. Add the tailwind imports at the top of the file:
@tailwind base;
@tailwind components;
@tailwind utilities;
2
3
Make sure that you are importing the globals.css file into your root layout.jsx file so tailwind styles can be used across your whole application.
With this configuration and set up completed, you can now use the Tailwind classes through your pages and components.
export default function Page() {
return <h1 className="text-3xl font-bold underline">Styled using Tailwind classes</h1>;
}
2
3
The Tailwind site documentation (opens new window) has a easily searched list of styles.
Some of the items that you will use most often have to do with font-sizes, padding, margin, and color.
# Font-size
To set font-sizes for any element you can use the class names: text-xs, text-sm, text-base, text-lg, text-xl, text-2xl, or text-3xl. Each of these classes represent a font-size plus a
line-height. If you want to set a specific line-height with any font-size, just add /[ ] after the text-* part. Inside the [] you can put the override value for the line-height. Eg:
text-sm/[4rem] will use the text-sm font-size and then a line-height of 4rem will be used.
If you want to change the font-size based on a breakpoint you can prefix each size with a breakpoint label. Eg: text-sm md:text-base lg:text-lg would apply text-sm as the font-size up to the
medium breakpoint where it will start to use text-base and then at the large screen breakpoint switch to text-lg.
font-size reference (opens new window).
These sizes all have default values. If you want, you can override them in the tailwind.config.js file at the root of the project. Inside the theme section, add an extend property if it doesn't
exist. Inside that you can add a fontSize object and set values for all the sizes.
module.exports = {
theme: {
extend: {
fontSize: {
sm: '0.8rem',
base: '1rem',
xl: '1.25rem',
'2xl': '1.563rem',
'3xl': '1.953rem',
'4xl': '2.441rem',
'5xl': '3.052rem',
},
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
If you add settings in the tailwind.config.js file inside of the theme property you are basically creating a new version of the setting. So, fontSize would replace the default fontSize
entirely.
If you place the property inside of theme.extend, then you are adding values to the default. If the property name inside theme.extend.fontSize matches, then you are overriding the default. If it
doesn't exist in the default then you are adding it as a new value.
If you want to create a new set of sizes, the https://type-scale.com (opens new window) website is great.
# Padding and Margin
Padding and Margin classNames start with of p- or m- followed by a number. The number refers to a value from the default spacing scale in tailwind. If you want to override those values for your
site, edit your tailwind.config.js file and add a spacing property to the theme.
module.exports = {
theme: {
spacing: {
1: '8px',
2: '12px',
3: '16px',
4: '24px',
5: '32px',
6: '48px',
},
},
};
2
3
4
5
6
7
8
9
10
11
12
You can add one of those numbers after the p- or m- to apply the distance to all four sides. If you want to only apply the spacing to the top and bottom use py- or my- followed by the number.
Left and right can be set with the classNames px- or my- and the number.
If you want to set the four sides use pt-*, pr-*, pb-*, pl-* for top, right, bottom, and left. Same for margin just m instead of p.
# Colours
For the colours we use a prefix of text- or bg- to indicate if we are setting the colour for the text or the background.
After the prefix use the name of the colour. Then finish with the brightness level number of 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, or 950. Here are a few examples:
text-amber-400
text-blue-100
bg-zinc-50
bg-slate-950
2
3
4
colour reference page (opens new window). You can override any colours you want or override the existing values. See the Colour reference page for the details on
overriding. The process is just like the sizing and spacing with the edits to the tailwind.config.js file.
# Hovering Changes
For any className in Tailwind, you can prefix it with hover: and it becomes a class that only gets applied when the user hovers over the element. active: and focus: are also available.
# Breakpoints
If you want any className to only apply in specific breakpoints then you can add one of the breakpoint prefixes: sm, md, lg, xl, or 2xl.
| Prefix | min width | CSS |
|---|---|---|
| sm | 640px | @media (min-width: 640px) { ... } |
| md | 768px | @media (min-width: 768px) { ... } |
| lg | 1024px | @media (min-width: 1024px) { ... } |
| xl | 1280px | @media (min-width: 1280px) { ... } |
| 2xl | 1536px | @media (min-width: 1536px) { ... } |
Breakpoint reference (opens new window)
If you want to change these sizes, use the tailwind.config.js file.
module.exports = {
theme: {
screens: {
sm: '480px',
md: '768px',
lg: '976px',
xl: '1440px',
},
},
};
2
3
4
5
6
7
8
9
10
# Dark Mode
Dark Mode reference (opens new window) for Tailwind in Next.js
# Building a Theme with Tailwind
Tailwind comes with a series of directives that you can use in your /app/globals.css file to create reusabled classes that combine your own designs with the built-in Tailwind utility classes.
Tailwind is a very convenient way to add styling to the returned JSX from a page.js file.
The downside of doing this is the amount of repetition that you need have across all the components and pages. While each Tailwind class might be a wrapper around 6 CSS properties, if you want to use the same 5 Tailwind classes on six different components, on each page, then that is a lot of repetition.
So, go back to what we do in basic HTML and CSS. Instead of adding a style attribute with a long list of CSS properties and values, we add one CSS className and put all the properties into the one CSS file.
Treat the Tailwind classnames as individual style properties. We want to group all the required Tailwind classes together as a single CSS class inside of globals.css. Then we only need one
descriptive class name in the JSX.
# @apply directive
The @apply directive allows you to add one or more Tailwind classes to your own CSS class.
The @tailwind directive allows you to import the base collections of Tailwind classes from the groups base, components, and utilities.
The @layout directive allows you to create your own classes and ADD them to a Tailwind groups base, components, and utilities. This way you can control the order of loading the styles
(classes) and it allows you to override them easier.
CSS in your Next.js application will be loaded in the order:
- @tailwind base group
- @tailwind components group
- @tailwind utilities group
- the globals.css file
- the url segment specific *.module.css files
- inline styles within the components
Inside each group, normal CSS specificity applies.
/* globals.css */
/* import the tailwind layers */
@tailwind base;
@tailwind components;
@tailwind utilities;
.shinyThing {
/* this is a general class available to use on any page */
padding-block: 1rem;
}
@layer base {
/* any classes inside here will be grouped with the base layer
which will help with being able to override the values */
.notShinyThing {
/* another class available to use on any page */
padding-block: 1rem;
}
.partlyShinyThing {
@apply rounded px-1 py-3 text-white bg-skyblue-600;
/* include all these tailwind classes, as part of this class, inside the base layer */
font-family: sans-serif;
}
}
.genericThing {
font-family: serif;
@apply rounded;
@apply px-1 mx-2 text-slate-800;
/* apply can be used here too, multiple times if desired */
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Use the @apply directive to bring together one or more Tailwind classes inside a single CSS class of your own. This way you can use your own class names inside your JSX components.
//page.js
export default function Pages(props) {
return (
<div className="genericThing">
<p className="shinyThing">Lorem Ipsum</p>
<p className="notShinyThing">Lorem Ipsum</p>
<p className="partlyShinyThing">Lorem Ipsum</p>
</div>
);
}
2
3
4
5
6
7
8
9
10
11
No imports required in the above example because all four class names existed inside of globals.css.
Much easier to read. Much less to write.
Another reason to add classes into the @layer groups is that your class can now used in conjunction with the modifiers like :md, :lg, :xl, :hover, and :active.
return (
<div className="sm:notShinyThing md:partlyShinyThing lg:shinyThing">
<p>The applied class changes as the viewport size changes</p>
</div>
);
2
3
4
5
Reference for the layer directive in Tailwind (opens new window)
# theme() function
Tailwind also has a function theme(), which will let you directly access settings inside the theme object of the tailwind.config.js file.
/* globals.css or *.module.css */
.content-area {
height: calc(100vh - theme(spacing.128));
}
2
3
4
5
The above example would be access the tailwind.config.js file and pulls the value from the module.exports object.
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
extend: {
spacing: {
128: '32rem',
144: '36rem',
},
borderRadius: {
'4xl': '2rem',
},
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
Specifically, if will get the 32rem value from the theme.extend.spacing['128'] property.
Reference for the theme() and directives in Tailwind (opens new window)
# Image Config
When loading images in a Next.js application remember that you can use the <Image> component.
import Image from 'next/image';
You will also need to configure the allowed domains for images. Edit the next.config.mjs file at the root of your project. See the
image config reference page here (opens new window).
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'storage.googleapis.com',
},
],
},
};
export default nextConfig;
2
3
4
5
6
7
8
9
10
11
12
13
# What to do this week
TODO Things to do before next week.
- Read all the content from
Modules 13.1, 13.2, and 14.1. - Finish watching the React in 2021 Video Tutorial Playlist (opens new window)