.
This commit is contained in:
+458
@@ -0,0 +1,458 @@
|
||||
---
|
||||
title: CSS
|
||||
description: Learn about the different ways to add CSS to your application, including Tailwind CSS, CSS Modules, Global CSS, and more.
|
||||
related:
|
||||
title: Next Steps
|
||||
description: Learn more about the alternatives ways you can use CSS in your application.
|
||||
links:
|
||||
- app/guides/tailwind-v3-css
|
||||
- app/guides/sass
|
||||
- app/guides/css-in-js
|
||||
---
|
||||
|
||||
Next.js provides several ways to style your application using CSS, including:
|
||||
|
||||
- [Tailwind CSS](#tailwind-css)
|
||||
- [CSS Modules](#css-modules)
|
||||
- [Global CSS](#global-css)
|
||||
- [External Stylesheets](#external-stylesheets)
|
||||
- [Sass](/docs/app/guides/sass)
|
||||
- [CSS-in-JS](/docs/app/guides/css-in-js)
|
||||
|
||||
## Tailwind CSS
|
||||
|
||||
[Tailwind CSS](https://tailwindcss.com/) is a utility-first CSS framework that provides low-level utility classes to build custom designs.
|
||||
|
||||
<AppOnly>
|
||||
|
||||
Install Tailwind CSS:
|
||||
|
||||
```bash package="pnpm"
|
||||
pnpm add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="npm"
|
||||
npm install -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="yarn"
|
||||
yarn add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="bun"
|
||||
bun add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
Add the PostCSS plugin to your `postcss.config.mjs` file:
|
||||
|
||||
```js filename="postcss.config.mjs"
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Import Tailwind in your global CSS file:
|
||||
|
||||
```css filename="app/globals.css"
|
||||
@import 'tailwindcss';
|
||||
```
|
||||
|
||||
Import the CSS file in your root layout:
|
||||
|
||||
```tsx filename="app/layout.tsx" switcher
|
||||
import './globals.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/layout.js" switcher
|
||||
import './globals.css'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Now you can start using Tailwind's utility classes in your application:
|
||||
|
||||
```tsx filename="app/page.tsx" switcher
|
||||
export default function Page() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<h1 className="text-4xl font-bold">Welcome to Next.js!</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/page.js" switcher
|
||||
export default function Page() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<h1 className="text-4xl font-bold">Welcome to Next.js!</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
Install Tailwind CSS:
|
||||
|
||||
```bash package="pnpm"
|
||||
pnpm add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="npm"
|
||||
npm install -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="yarn"
|
||||
yarn add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
```bash package="bun"
|
||||
bun add -D tailwindcss @tailwindcss/postcss
|
||||
```
|
||||
|
||||
Add the PostCSS plugin to your `postcss.config.mjs` file:
|
||||
|
||||
```js filename="postcss.config.mjs"
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Import Tailwind in your global CSS file:
|
||||
|
||||
```css filename="styles/globals.css"
|
||||
@import 'tailwindcss';
|
||||
```
|
||||
|
||||
Import the CSS file in your `pages/_app.js` file:
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
import '@/styles/globals.css'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
Now you can start using Tailwind's utility classes in your application:
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<h1 className="text-4xl font-bold">Welcome to Next.js!</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<h1 className="text-4xl font-bold">Welcome to Next.js!</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
> **Good to know:** If you need broader browser support for very old browsers, see the [Tailwind CSS v3 setup instructions](/docs/app/guides/tailwind-v3-css).
|
||||
|
||||
## CSS Modules
|
||||
|
||||
CSS Modules locally scope CSS by generating unique class names. This allows you to use the same class in different files without worrying about naming collisions.
|
||||
|
||||
<AppOnly>
|
||||
|
||||
To start using CSS Modules, create a new file with the extension `.module.css` and import it into any component inside the `app` directory:
|
||||
|
||||
```css filename="app/blog/blog.module.css"
|
||||
.blog {
|
||||
padding: 24px;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx filename="app/blog/page.tsx" switcher
|
||||
import styles from './blog.module.css'
|
||||
|
||||
export default function Page() {
|
||||
return <main className={styles.blog}></main>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/blog/page.js" switcher
|
||||
import styles from './blog.module.css'
|
||||
|
||||
export default function Layout() {
|
||||
return <main className={styles.blog}></main>
|
||||
}
|
||||
```
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
To start using CSS Modules, create a new file with the extension `.module.css` and import it into any component inside the `pages` directory:
|
||||
|
||||
```css filename="/styles/blog.module.css"
|
||||
.blog {
|
||||
padding: 24px;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx filename="pages/blog/index.tsx" switcher
|
||||
import styles from './blog.module.css'
|
||||
|
||||
export default function Page() {
|
||||
return <main className={styles.blog}></main>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/blog/index.js" switcher
|
||||
import styles from './blog.module.css'
|
||||
|
||||
export default function Page() {
|
||||
return <main className={styles.blog}></main>
|
||||
}
|
||||
```
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
## Global CSS
|
||||
|
||||
You can use global CSS to apply styles across your application.
|
||||
|
||||
<AppOnly>
|
||||
|
||||
Create a `app/global.css` file and import it in the root layout to apply the styles to **every route** in your application:
|
||||
|
||||
```css filename="app/global.css"
|
||||
body {
|
||||
padding: 20px 20px 60px;
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx filename="app/layout.tsx" switcher
|
||||
// These styles apply to every route in the application
|
||||
import './global.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/layout.js" switcher
|
||||
// These styles apply to every route in the application
|
||||
import './global.css'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know:** Global styles can be imported into any layout, page, or component inside the `app` directory. However, since Next.js uses React's built-in support for stylesheets to integrate with Suspense, this currently does not remove stylesheets as you navigate between routes which can lead to conflicts. We recommend using global styles for _truly_ global CSS (like Tailwind's base styles), [Tailwind CSS](#tailwind-css) for component styling, and [CSS Modules](#css-modules) for custom scoped CSS when needed.
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
Import the stylesheet in the `pages/_app.js` file to apply the styles to **every route** in your application:
|
||||
|
||||
```tsx filename="pages/_app.js"
|
||||
import '@/styles/global.css'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
Due to the global nature of stylesheets, and to avoid conflicts, you should import them inside [`pages/_app.js`](/docs/pages/building-your-application/routing/custom-app).
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
## External stylesheets
|
||||
|
||||
<AppOnly>
|
||||
|
||||
Stylesheets published by external packages can be imported anywhere in the `app` directory, including colocated components:
|
||||
|
||||
```tsx filename="app/layout.tsx" switcher
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className="container">{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="app/layout.js" switcher
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className="container">{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know:** In React 19, `<link rel="stylesheet" href="..." />` can also be used. See the [React `link` documentation](https://react.dev/reference/react-dom/components/link) for more information.
|
||||
|
||||
</AppOnly>
|
||||
|
||||
<PagesOnly>
|
||||
|
||||
Next.js allows you to import CSS files from a JavaScript file. This is possible because Next.js extends the concept of [`import`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import) beyond JavaScript.
|
||||
|
||||
### Import styles from `node_modules`
|
||||
|
||||
Since Next.js **9.5.4**, importing a CSS file from `node_modules` is permitted anywhere in your application.
|
||||
|
||||
For global stylesheets, like `bootstrap` or `nprogress`, you should import the file inside `pages/_app.js`. For example:
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
To import CSS required by a third-party component, you can do so in your component. For example:
|
||||
|
||||
```jsx filename="components/example-dialog.js"
|
||||
import { useState } from 'react'
|
||||
import { Dialog } from '@reach/dialog'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
import '@reach/dialog/styles.css'
|
||||
|
||||
function ExampleDialog(props) {
|
||||
const [showDialog, setShowDialog] = useState(false)
|
||||
const open = () => setShowDialog(true)
|
||||
const close = () => setShowDialog(false)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={open}>Open Dialog</button>
|
||||
<Dialog isOpen={showDialog} onDismiss={close}>
|
||||
<button className="close-button" onClick={close}>
|
||||
<VisuallyHidden>Close</VisuallyHidden>
|
||||
<span aria-hidden>×</span>
|
||||
</button>
|
||||
<p>Hello there. I am a dialog</p>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</PagesOnly>
|
||||
|
||||
## Ordering and Merging
|
||||
|
||||
Next.js optimizes CSS during production builds by automatically chunking (merging) stylesheets. The **order of your CSS** depends on the **order you import styles in your code**.
|
||||
|
||||
For example, `base-button.module.css` will be ordered before `page.module.css` since `<BaseButton>` is imported before `page.module.css`:
|
||||
|
||||
```tsx filename="page.tsx" switcher
|
||||
import { BaseButton } from './base-button'
|
||||
import styles from './page.module.css'
|
||||
|
||||
export default function Page() {
|
||||
return <BaseButton className={styles.primary} />
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="page.js" switcher
|
||||
import { BaseButton } from './base-button'
|
||||
import styles from './page.module.css'
|
||||
|
||||
export default function Page() {
|
||||
return <BaseButton className={styles.primary} />
|
||||
}
|
||||
```
|
||||
|
||||
```tsx filename="base-button.tsx" switcher
|
||||
import styles from './base-button.module.css'
|
||||
|
||||
export function BaseButton() {
|
||||
return <button className={styles.primary} />
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="base-button.js" switcher
|
||||
import styles from './base-button.module.css'
|
||||
|
||||
export function BaseButton() {
|
||||
return <button className={styles.primary} />
|
||||
}
|
||||
```
|
||||
|
||||
### Recommendations
|
||||
|
||||
To keep CSS ordering predictable:
|
||||
|
||||
- Try to contain CSS imports to a single JavaScript or TypeScript entry file
|
||||
- Import global styles and Tailwind stylesheets in the root of your application.
|
||||
- **Use Tailwind CSS** for most styling needs as it covers common design patterns with utility classes.
|
||||
- Use CSS Modules for component-specific styles when Tailwind utilities aren't sufficient.
|
||||
- Use a consistent naming convention for your CSS modules. For example, using `<name>.module.css` over `<name>.tsx`.
|
||||
- Extract shared styles into shared components to avoid duplicate imports.
|
||||
- Turn off linters or formatters that auto-sort imports like ESLint’s [`sort-imports`](https://eslint.org/docs/latest/rules/sort-imports).
|
||||
- You can use the [`cssChunking`](/docs/app/api-reference/config/next-config-js/cssChunking) option in `next.config.js` to control how CSS is chunked.
|
||||
|
||||
## Development vs Production
|
||||
|
||||
- In development (`next dev`), CSS updates apply instantly with [Fast Refresh](/docs/architecture/fast-refresh).
|
||||
- In production (`next build`), all CSS files are automatically concatenated into **many minified and code-split** `.css` files, ensuring the minimal amount of CSS is loaded for a route.
|
||||
- CSS still loads with JavaScript disabled in production, but JavaScript is required in development for Fast Refresh.
|
||||
- CSS ordering can behave differently in development, always ensure to check the build (`next build`) to verify the final CSS order.
|
||||
Reference in New Issue
Block a user