Skip to main content

Styling and Layout

tip

This section focuses on styling through stylesheets.
For advanced customizations (DOM structure, React code…), refer to the Swizzling Guide.

A Docusaurus site is a single-page React application, so you can style it the same way you style React apps.

You can choose from different approaches depending on your needs.
Highly interactive web apps may benefit from co-located component styles, while smaller static sites can use global stylesheets.

Global Styles​

The simplest approach is global CSS, which is ideal for small websites or light customizations.

If you're using @docusaurus/preset-classic, create your CSS file (e.g., /src/css/custom.css) and import it globally in your config:

docusaurus.config.js
export default {
presets: [
[
'@docusaurus/preset-classic',
{
theme: {
customCss: ['./src/css/custom.css'],
},
},
],
],
};

Example global CSS:

/src/css/custom.css
.purple-text {
color: rebeccapurple;
}

Use it directly inside your components:

function MyComponent() {
return <h1 className="purple-text">Purple Heading!</h1>;
}

Class Name Types​

When adding custom styles, you may encounter:

  • Theme class names – stable and safe to target.
  • Infima class names – follow BEM convention. Generally stable but still internal.
  • CSS module hashes – end with a hash (codeBlockContainer_RIuc). Avoid targeting directly; use attribute selectors if needed.

Theme Class Names​

We provide stable theme-agnostic class names for maintainable layout styling.

Click to view stable class names
export const ThemeClassNames = {
page: {
blogListPage: 'blog-list-page',
blogPostPage: 'blog-post-page',
blogTagsListPage: 'blog-tags-list-page',
blogTagPostListPage: 'blog-tags-post-list-page',
blogAuthorsListPage: 'blog-authors-list-page',
blogAuthorsPostsPage: 'blog-authors-posts-page',
docsDocPage: 'docs-doc-page',
docsTagsListPage: 'docs-tags-list-page',
docsTagDocListPage: 'docs-tags-doc-list-page',
mdxPage: 'mdx-page',
},
wrapper: {
main: 'main-wrapper',
blogPages: 'blog-wrapper',
docsPages: 'docs-wrapper',
mdxPages: 'mdx-wrapper',
},
common: {
editThisPage: 'theme-edit-this-page',
lastUpdated: 'theme-last-updated',
backToTopButton: 'theme-back-to-top-button',
codeBlock: 'theme-code-block',
admonition: 'theme-admonition',
unlistedBanner: 'theme-unlisted-banner',
draftBanner: 'theme-draft-banner',
admonitionType: (type: string) => `theme-admonition-${type}`,
},
announcementBar: {
container: 'theme-announcement-bar',
},
tabs: {
container: 'theme-tabs-container',
},
layout: {
navbar: {
container: 'theme-layout-navbar',
containerLeft: 'theme-layout-navbar-left',
containerRight: 'theme-layout-navbar-right',
mobileSidebar: {
container: 'theme-layout-navbar-sidebar',
panel: 'theme-layout-navbar-sidebar-panel',
},
},
main: {
container: 'theme-layout-main',
},
footer: {
container: 'theme-layout-footer',
column: 'theme-layout-footer-column',
},
},
docs: {
docVersionBanner: 'theme-doc-version-banner',
docVersionBadge: 'theme-doc-version-badge',
docBreadcrumbs: 'theme-doc-breadcrumbs',
docMarkdown: 'theme-doc-markdown',
docTocMobile: 'theme-doc-toc-mobile',
docTocDesktop: 'theme-doc-toc-desktop',
docFooter: 'theme-doc-footer',
docFooterTagsRow: 'theme-doc-footer-tags-row',
docFooterEditMetaRow: 'theme-doc-footer-edit-meta-row',
docSidebarContainer: 'theme-doc-sidebar-container',
docSidebarMenu: 'theme-doc-sidebar-menu',
docSidebarItemCategory: 'theme-doc-sidebar-item-category',
docSidebarItemLink: 'theme-doc-sidebar-item-link',
docSidebarItemCategoryLevel: (level: number) =>
`theme-doc-sidebar-item-category-level-${level}` as const,
docSidebarItemLinkLevel: (level: number) =>
`theme-doc-sidebar-item-link-level-${level}` as const,
},
blog: {
blogFooterTagsRow: 'theme-blog-footer-tags-row',
blogFooterEditMetaRow: 'theme-blog-footer-edit-meta-row',
},
pages: {
pageFooterEditMetaRow: 'theme-pages-footer-edit-meta-row',
},
} as const;

Styling with Infima​

Docusaurus classic theme uses Infima for base layout and components.

You can override Infima CSS variables globally:

/src/css/custom.css
:root {
--ifm-color-primary: #25c2a0;
--ifm-code-font-size: 95%;
}

Infima uses 7 shades per color. Use ColorBox or the generator below to create your shades:

tip

Aim for at least WCAG-AA contrast ratio for the primary color to ensure readability. Use the Docusaurus website itself to preview how your color palette would look like. You can use alternative palettes in dark mode because one color doesn't usually work in both light and dark mode.

CSS Variable NameHexAdjustmentContrast Rating
--ifm-color-primary-lightest#3cad6eFail πŸ”΄
--ifm-color-primary-lighter#359962Fail πŸ”΄
--ifm-color-primary-light#33925dFail πŸ”΄
--ifm-color-primary#2e85550AA πŸ‘
--ifm-color-primary-dark#29784cAA πŸ‘
--ifm-color-primary-darker#277148AA πŸ‘
--ifm-color-primary-darkest#205d3bAAA πŸ…

Replace the variables in src/css/custom.css with these new variables.

/src/css/custom.css
:root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
--ifm-color-primary-darkest: #205d3b;
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
}

Dark Mode​

The <html> element switches its data-theme attribute:

  • Light mode β†’ data-theme="light"
  • Dark mode β†’ data-theme="dark"

Example:

[data-theme='dark'] {
--ifm-color-primary: #4e89e8;
}
[data-theme='dark'] .purple-text {
color: plum;
}

Data Attributes​

You can inject <html> data attributes via query strings (docusaurus-data-<key>):

/src/css/custom.css
html[data-navbar='false'] .navbar {
display: none;
}

html[data-red-border] div#__docusaurus {
border: thick solid red;
}
/docs/?docusaurus-data-navbar=false&docusaurus-data-red-border

Useful for embedding docs in iframes with custom layouts.

Mobile View​

The default breakpoint between desktop and mobile is 996px. Use media queries for responsive layouts:

.banner {
padding: 4rem;
}

@media screen and (max-width: 996px) {
.banner {
padding: 2rem;
}
}

CSS Modules​

For component-scoped styles, name files with .module.css:

styles.module.css
.main {
padding: 12px;
}
.heading {
font-weight: bold;
}
import styles from './styles.module.css';

export default function MyComponent() {
return (
<main className={styles.main}>
<h1 className={styles.heading}>Hello!</h1>
</main>
);
}

Webpack automatically generates unique class names.

Sass/SCSS​

To use Sass/SCSS, install the plugin:

npm install --save docusaurus-plugin-sass sass

Add it to docusaurus.config.js:

docusaurus.config.js
export default {
plugins: ['docusaurus-plugin-sass'],
};

Global Sass Example​

docusaurus.config.js
export default {
presets: [
[
'@docusaurus/preset-classic',
{
theme: {
customCss: ['./src/css/custom.scss'],
},
},
],
],
};

Module Sass Example​

Use .module.scss for scoped Sass modules:

styles.module.scss
.main {
padding: 12px;

article {
color: #ccc;
}
}
import styles from './styles.module.scss';

function MyComponent() {
return (
<main className={styles.main}>
<article>Lorem Ipsum</article>
</main>
);
}

TypeScript Support​

Update tsconfig.json:

{
"extends": "@docusaurus/tsconfig",
"compilerOptions": {
+ "types": ["docusaurus-plugin-sass"]
}
}