Skip to main content
@mintlify/components includes built-in dark mode support with automatic theme detection. Components automatically adapt their appearance based on a dark class on the root HTML element.

How Dark Mode Works

The library uses the .dark class selector pattern:
  • Light mode: No class on <html>
  • Dark mode: <html class="dark">
Components detect theme changes automatically and update their styling accordingly using Tailwind’s dark: variant.

Basic Setup

1

Add dark class toggle

Implement a way to toggle the dark class on your root HTML element:
import { useEffect, useState } from 'react';

function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    const isDarkMode = document.documentElement.classList.contains('dark');
    setIsDark(isDarkMode);
  }, []);

  const toggleTheme = () => {
    document.documentElement.classList.toggle('dark');
    setIsDark(!isDark);
  };

  return (
    <button onClick={toggleTheme}>
      {isDark ? 'Light Mode' : 'Dark Mode'}
    </button>
  );
}
2

Components update automatically

All @mintlify/components will automatically respond to the theme change:
import { Callout, Card, CodeBlock } from '@mintlify/components';

function App() {
  return (
    <>
      <ThemeToggle />
      <Callout variant="info">
        This callout adapts to dark mode automatically
      </Callout>
      <Card title="Dark Mode" icon="moon">
        Cards also adjust their colors
      </Card>
    </>
  );
}

Using next-themes

For Next.js applications, next-themes is the recommended approach for handling theme management.
1

Install next-themes

npm install next-themes
2

Add ThemeProvider

Wrap your application with the ThemeProvider:
app/layout.tsx
import { ThemeProvider } from 'next-themes';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system">
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
3

Create theme toggle

components/theme-toggle.tsx
'use client';

import { useTheme } from 'next-themes';
import { useEffect, useState } from 'react';

export function ThemeToggle() {
  const [mounted, setMounted] = useState(false);
  const { theme, setTheme } = useTheme();

  useEffect(() => setMounted(true), []);

  if (!mounted) return null;

  return (
    <button
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
      className="px-4 py-2 rounded-lg border"
    >
      {theme === 'dark' ? 'Light Mode' : 'Dark Mode'}
    </button>
  );
}

Detecting Theme in Components

You can create a custom hook to detect theme changes by observing the dark class on the document element:
import { useEffect, useState } from 'react';

const useIsDarkTheme = () => {
  const [isDarkTheme, setIsDarkTheme] = useState(false);

  useEffect(() => {
    const checkTheme = () => {
      setIsDarkTheme(document.documentElement.classList.contains('dark'));
    };

    // Check initial state
    checkTheme();

    // Watch for theme changes
    const observer = new MutationObserver(checkTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class'],
    });

    return () => observer.disconnect();
  }, []);

  return { isDarkTheme };
};

// Use in your components
function ThemeAwareComponent() {
  const { isDarkTheme } = useIsDarkTheme();
  
  return (
    <div>
      Current theme: {isDarkTheme ? 'dark' : 'light'}
    </div>
  );
}
This hook uses a MutationObserver to watch for class changes on the HTML element, allowing your components to react to theme changes in real-time.

Customizing Dark Mode Colors

Tailwind v4

Use CSS variables in your @theme block:
styles.css
@import "@mintlify/components/styles.css";
@import "tailwindcss";

@theme {
  /* Light mode colors */
  --color-primary: #3b82f6;
  --color-primary-light: #dbeafe;
  
  /* Dark mode colors */
  --color-primary-dark: #1e40af;
  --color-background-dark: #0f172a;
  --color-tooltip-foreground: #ffffff;
}

Tailwind v3

Extend dark mode colors in your config:
tailwind.config.js
module.exports = {
  darkMode: 'class', // Required!
  theme: {
    extend: {
      colors: {
        primary: {
          DEFAULT: '#3b82f6',
          light: '#dbeafe',
          dark: '#1e40af',
        },
      },
    },
  },
}
For Tailwind v3, you must set darkMode: 'class' in your config for dark mode to work with the components.

Component-Specific Dark Mode

Callout Component

Callouts automatically adapt their colors in dark mode using predefined color schemes:
import { Callout } from '@mintlify/components';

// Info variant - from source/packages/components/src/components/callout/callout.tsx:36-43
// Light: border-stone-200 bg-stone-50
// Dark: border-stone-700 bg-white/10
<Callout variant="info">
  This note looks great in both themes
</Callout>

// Warning variant - from source/packages/components/src/components/callout/callout.tsx:44-50
// Light: border-yellow-200 bg-yellow-50 text-yellow-800
// Dark: border-yellow-900 bg-yellow-600/20 text-yellow-300
<Callout variant="warning">
  Warnings use yellow tones that adapt automatically
</Callout>

// Custom colors also work in dark mode
<Callout variant="custom" color="#8b5cf6">
  Custom color with automatic dark mode adjustment
</Callout>

Accordion Component

Accordions use adaptive borders and backgrounds:
import { Accordion } from '@mintlify/components';

// From source/packages/components/src/components/accordion/accordion.tsx:204-207
// Light: border-stone-200/70 bg-white
// Dark: border-white/10 bg-[#0b0c0e]
<Accordion title="Getting Started">
  Accordion content adapts to dark mode
</Accordion>

Badge Component

Badges use CSS variables for dynamic color adaptation:
import { Badge } from '@mintlify/components';

// From source/packages/components/src/components/badge/badge.tsx:31-32
// Blue badge uses:
// Light: bg-[#E3EAFD] text-[#133A9A]
// Dark: bg-[#07296A] text-[#7196F4]
<Badge color="blue">TypeScript</Badge>

// Green badge uses:
// Light: bg-[#D1FAE4] text-[#166E3F]
// Dark: bg-[#0F4C2C] text-[#6AE1A1]
<Badge color="green">Success</Badge>

Code Blocks

Code blocks use Shiki for syntax highlighting with dual themes:
import { CodeBlock } from '@mintlify/components';

<CodeBlock
  code={`console.log('Hello World');`}
  language="javascript"
/>
The code block automatically switches between light and dark syntax themes based on the current mode.

Custom Dark Mode Styles

For your own components, use Tailwind’s dark: variant:
<div className="bg-white dark:bg-stone-950 text-black dark:text-white">
  Responsive to theme
</div>

<div className="border border-stone-200 dark:border-stone-700">
  Adaptive borders
</div>

<div className="shadow-lg dark:shadow-none">
  Different shadows per theme
</div>

CSS Variables for Dark Mode

The library uses several CSS variables that adapt to dark mode:
/* Code block fade overlay */
--fade-color-light: /* Light mode background */
--fade-color-dark: /* Dark mode background */
--background-light: /* Default light background */
--background-dark: /* Default dark background */

/* Shiki syntax highlighting */
--shiki-light: /* Light theme text color */
--shiki-dark: /* Dark theme text color */
--shiki-light-bg: /* Light theme background */
--shiki-dark-bg: /* Dark theme background */
These variables are automatically managed by the components.

Persisting Theme Preference

import { useEffect, useState } from 'react';

function useTheme() {
  const [theme, setTheme] = useState(() => {
    if (typeof window !== 'undefined') {
      return localStorage.getItem('theme') || 'light';
    }
    return 'light';
  });

  useEffect(() => {
    const root = document.documentElement;
    if (theme === 'dark') {
      root.classList.add('dark');
    } else {
      root.classList.remove('dark');
    }
    localStorage.setItem('theme', theme);
  }, [theme]);

  return { theme, setTheme };
}

Troubleshooting

Verify that:
  1. The dark class is being toggled on the <html> element
  2. For Tailwind v3, darkMode: 'class' is set in your config
  3. Component styles are imported before Tailwind CSS
Check that you’re using the correct CSS variable names in your theme configuration. The components look for specific variables like --color-primary-dark.Also verify that the dark class is actually being applied to the HTML element using browser dev tools.
This happens when the theme is applied after initial render. Use suppressHydrationWarning on the <html> tag and apply the theme class before React hydrates:
<script>
  if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
    document.documentElement.classList.add('dark');
  } else {
    document.documentElement.classList.remove('dark');
  }
</script>
Ensure you’re importing the component styles at the top of your CSS file:
@import "@mintlify/components/styles.css";
The component styles include all necessary dark mode variants.

Next Steps

Tailwind Integration

Learn about Tailwind CSS setup and configuration

TypeScript

Explore TypeScript types and exports

Build docs developers (and LLMs) love