UNPKG

next

Version:

The React Framework

459 lines (345 loc) 12.4 kB
--- 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 Page() { 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.