# How to Create Custom CSS Themes and Styling in Docusaurus: Complete Guide

> Learn to create custom CSS themes and styling in Docusaurus. Customize global styles with customCss or use .module.css files for scoped component styling. Enhance your Docusaurus site.

- Repository: [Meta/docusaurus](https://github.com/facebook/docusaurus)
- Tags: how-to-guide
- Published: 2026-03-04

---

**You can customize Docusaurus styling by declaring global CSS files in the `customCss` option of `@docusaurus/preset-classic` for site-wide theming, or using [`.module.css`](https://github.com/facebook/docusaurus/blob/main/.module.css) files alongside React components for scoped, collision-free styles.**

Docusaurus provides a flexible architecture for visual customization through the Infima CSS framework without requiring you to eject core theme components. By leveraging the `customCss` configuration option in the classic preset, you can inject global styles that override default design tokens while maintaining upgrade compatibility. This article examines the source implementation in `facebook/docusaurus` to demonstrate how to create custom CSS themes and styling in Docusaurus using both global stylesheets and CSS Modules.

## Adding Global CSS with the `customCss` Option

The classic theme exposes a `customCss` configuration property that resolves file paths relative to your site directory and injects them into the final stylesheet bundle. According to the implementation in [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts) (lines 43-80), the preset automatically handles path resolution and bundling.

### Configuring the Classic Preset

Create a global stylesheet—conventionally at [`src/css/custom.css`](https://github.com/facebook/docusaurus/blob/main/src/css/custom.css)—then reference it in your [`docusaurus.config.js`](https://github.com/facebook/docusaurus/blob/main/docusaurus.config.js) or [`docusaurus.config.ts`](https://github.com/facebook/docusaurus/blob/main/docusaurus.config.ts) file:

```javascript
// docusaurus.config.js
module.exports = {
  presets: [
    [
      '@docusaurus/preset-classic',
      {
        theme: {
          customCss: ['./src/css/custom.css'],
        },
      },
    ],
  ],
};

```

The `customCss` property is defined in the TypeScript declarations at [`packages/docusaurus-theme-classic/src/theme-classic.d.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme-classic.d.ts) (lines 27-33) and validated by the Joi schema in [`packages/docusaurus-theme-classic/src/options.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/options.ts) (lines 485-500). The option accepts either a single string or an array of strings representing relative file paths.

### Overriding Infima CSS Variables

Infima, the underlying CSS framework, exposes CSS custom properties that control colors, typography, and spacing. Override these in your global CSS file to theme the entire site:

```css
/* src/css/custom.css */
:root {
  --ifm-color-primary: #ff6600;
  --ifm-color-primary-dark: #e65c00;
  --ifm-font-family-base: 'Open Sans', sans-serif;
  --ifm-link-color: #0066ff;
}

.navbar__brand {
  font-weight: bold;
}

```

Because Docusaurus injects your custom CSS after the default Infima stylesheet, your rules naturally take precedence without requiring `!important` overrides.

### Loading Multiple Stylesheets

The `customCss` option accepts an array, allowing you to organize styles into separate concerns such as variables, layouts, and component overrides:

```javascript
customCss: [
  './src/css/variables.css',
  './src/css/layout.css',
],

```

As implemented in [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts) (lines 71-79), Docusaurus resolves each path using `path.resolve(context.siteDir, p)` before pushing the modules into the Webpack/Rspack stylesheet pipeline.

## Using CSS Modules for Component-Scoped Styles

For styles that should apply only to specific theme components or custom React components, create **CSS Module** files with the [`.module.css`](https://github.com/facebook/docusaurus/blob/main/.module.css) extension alongside your component files:

```tsx
// src/theme/NavbarItem/CustomItem/index.tsx
import React from 'react';
import styles from './styles.module.css';

export default function CustomItem() {
  return <div className={styles.box}>Hello, styled world!</div>;
}

```

```css
/* src/theme/NavbarItem/CustomItem/styles.module.css */
.box {
  padding: 0.5rem 1rem;
  background: var(--ifm-color-primary);
  color: white;
  border-radius: 4px;
}

```

Docusaurus uses the standard Webpack/Rspack CSS Module loader to process these files. The loader automatically generates unique class names and exposes them via the imported `styles` object, preventing naming collisions across your codebase. No additional configuration is required to enable this behavior.

## Implementation Details from the Source Code

The theme entry point at [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts) orchestrates how custom CSS enters the build pipeline:

- **Path Resolution**: Each string in `customCss` is resolved relative to the site directory using Node's `path.resolve`
- **Validation**: The Joi schema in [`packages/docusaurus-theme-classic/src/options.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/options.ts) ensures paths are valid strings or arrays of strings
- **Injection**: Resolved modules are added to the bundler's entry points, ensuring your styles are included in the production build and hot-reloaded during development

The official `create-docusaurus` template demonstrates this configuration in [`packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts`](https://github.com/facebook/docusaurus/blob/main/packages/create-docusaurus/templates/classic-typescript/docusaurus.config.ts), providing a ready-to-use example of `customCss` integration.

## Summary

- **Global CSS**: Declare paths in the `customCss` option of `@docusaurus/preset-classic` to inject site-wide styles that override Infima variables
- **CSS Modules**: Use [`.module.css`](https://github.com/facebook/docusaurus/blob/main/.module.css) files for scoped, collision-free styling of specific components without affecting the global namespace
- **Multiple Files**: Pass an array to `customCss` to split your styles into logical, maintainable files
- **Variable Theming**: Override `--ifm-*` CSS variables in your global stylesheet to retheme the entire design system consistently
- **Source Authority**: The classic theme resolves and validates these options in [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts) and [`options.ts`](https://github.com/facebook/docusaurus/blob/main/options.ts)

## Frequently Asked Questions

### Can I use multiple CSS files for different theming concerns?

Yes. The `customCss` option accepts an array of file paths, allowing you to separate variables, layouts, and component-specific overrides into distinct files. Docusaurus resolves each path with `path.resolve(context.siteDir, p)` as shown in [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts) (lines 71-79) and bundles them in the order specified.

### Why should I use CSS Modules instead of global CSS?

CSS Modules generate unique class names scoped to the importing component, preventing style leakage and naming conflicts across your site. Use them when building custom theme components or swizzled components where styles should remain isolated. Global CSS is better suited for overriding Infima variables or applying site-wide branding that affects multiple pages.

### Where does Docusaurus validate the `customCss` configuration?

The classic theme validates the `customCss` option using a Joi schema defined in [`packages/docusaurus-theme-classic/src/options.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/options.ts) (lines 485-500). TypeScript definitions in [`packages/docusaurus-theme-classic/src/theme-classic.d.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme-classic.d.ts) (lines 27-33) provide compile-time type safety, ensuring your configuration contains valid file path strings before the build process begins.

### How do I ensure my custom styles override the default theme?

Docusaurus injects your `customCss` files after the default Infima stylesheet in the bundle pipeline defined in [`packages/docusaurus-theme-classic/src/index.ts`](https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/index.ts). Because of the cascading nature of CSS, your rules take precedence when selectors have equal specificity. For Infima variables, redefining them in `:root` automatically propagates changes throughout the component tree without needing to target specific selectors.