Theming

Implementing and customizing themes in your application using next-themes

Installation

Make sure you have next-themes installed:

npm install next-themes

Theme Provider Setup

Create a new file components/theme-provider.jsx:

'use client'
import * as React from 'react'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
export function ThemeProvider({ children, ...props }) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}

Then, update your layout file to use the theme provider:

import { ThemeProvider } from '@/components/theme-provider'
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
themes={['light', 'dark', 'modern']}
>
{children}
</ThemeProvider>
</body>
</html>
)
}

Theme Toggle Component

Create a theme toggle component to let users switch between themes:

'use client'
import { useTheme } from 'next-themes'
import { Button } from '@/components/ui/Button'
import { SunIcon, MoonIcon, LaptopIcon } from 'lucide-react'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<div className="flex gap-2">
<Button
variant="outline"
size="icon"
onClick={() => setTheme('light')}
aria-label="Light Mode"
>
<SunIcon className="h-[1.2rem] w-[1.2rem]" />
</Button>
<Button
variant="outline"
size="icon"
onClick={() => setTheme('dark')}
aria-label="Dark Mode"
>
<MoonIcon className="h-[1.2rem] w-[1.2rem]" />
</Button>
<Button
variant="outline"
size="icon"
onClick={() => setTheme('system')}
aria-label="System Mode"
>
<LaptopIcon className="h-[1.2rem] w-[1.2rem]" />
</Button>
</div>
)
}

Available Themes

The Blueprint UI Library comes with several built-in themes:

  • Light: Default light mode with clean, professional styling
  • Dark: Sophisticated dark theme with deep, rich tones
  • Modern: Metallic blue architectural theme with unique accent colors

These themes are defined in the globals.css file and can be accessed via the theme provider.

Using Themes in Components

You can access the current theme in your components using the useTheme hook:

'use client'
import { useTheme } from 'next-themes'
export function ThemeAwareComponent() {
const { theme, setTheme } = useTheme()
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme('dark')}>
Switch to dark mode
</button>
</div>
)
}

Creating a Custom Theme

To create a custom theme, you can use inline styles on the root element:

// Apply theme variables as inline styles
document.documentElement.style.setProperty('--background', '210 40% 98%');
document.documentElement.style.setProperty('--foreground', '210 40% 10%');
document.documentElement.style.setProperty('--card', '0 0% 100%');
document.documentElement.style.setProperty('--card-foreground', '210 40% 10%');
document.documentElement.style.setProperty('--popover', '0 0% 100%');
document.documentElement.style.setProperty('--popover-foreground', '210 40% 10%');
document.documentElement.style.setProperty('--primary', '210 100% 50%');
document.documentElement.style.setProperty('--primary-foreground', '0 0% 100%');
document.documentElement.style.setProperty('--secondary', '210 40% 90%');
document.documentElement.style.setProperty('--secondary-foreground', '210 40% 10%');
document.documentElement.style.setProperty('--muted', '210 40% 90%');
document.documentElement.style.setProperty('--muted-foreground', '210 40% 40%');
document.documentElement.style.setProperty('--accent', '210 40% 85%');
document.documentElement.style.setProperty('--accent-foreground', '210 40% 10%');
document.documentElement.style.setProperty('--destructive', '0 100% 50%');
document.documentElement.style.setProperty('--destructive-foreground', '0 0% 100%');
document.documentElement.style.setProperty('--success', '145 80% 40%');
document.documentElement.style.setProperty('--success-foreground', '0 0% 100%');
document.documentElement.style.setProperty('--border', '210 40% 90%');
document.documentElement.style.setProperty('--input', '210 40% 90%');
document.documentElement.style.setProperty('--ring', '210 100% 50%');
document.documentElement.style.setProperty('--chart-1', '210 100% 50%');
document.documentElement.style.setProperty('--chart-2', '240 100% 50%');
document.documentElement.style.setProperty('--chart-3', '280 100% 50%');
document.documentElement.style.setProperty('--chart-4', '320 100% 50%');
document.documentElement.style.setProperty('--chart-5', '360 100% 50%');

Then, use the ThemeProvider with your desired themes:

<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
themes={['light', 'dark', 'modern']}
>
{children}
</ThemeProvider>

CSS Variables

Our theming system uses CSS variables for colors. Here are the key variables used:

:root {
--background: 0 0% 100%; /* Page background */
--foreground: 0 0% 12%; /* Text color */
--card: 0 0% 100%; /* Card background */
--card-foreground: 0 0% 12%; /* Card text */
--primary: 220 14% 24%; /* Primary color (buttons, links) */
--primary-foreground: 0 0% 98%; /* Text on primary color */
--secondary: 220 5% 96%; /* Secondary color */
--secondary-foreground: 220 14% 20%; /* Text on secondary */
--muted: 220 5% 94%; /* Muted backgrounds */
--muted-foreground: 220 5% 45%; /* Muted text */
--accent: 220 5% 92%; /* Accent color */
--accent-foreground: 220 14% 20%; /* Text on accent */
--destructive: 0 72% 56%; /* Error states */
--destructive-foreground: 0 0% 98%; /* Text on error */
--success: 142 60% 36%; /* Success states */
--success-foreground: 0 0% 98%; /* Text on success */
--border: 220 7% 85%; /* Border color */
--input: 220 7% 85%; /* Input borders */
--ring: 220 14% 24%; /* Focus rings */
/* Chart colors for data visualization */
--chart-1: 220 60% 55%;
--chart-2: 190 50% 50%;
--chart-3: 15 60% 45%;
--chart-4: 275 40% 50%;
--chart-5: 45 60% 50%;
--radius: 0.5rem; /* Border radius */
}

These CSS variables are formatted as HSL values (hue, saturation, lightness) without the hsl() function. They are used with the hsl() function in your Tailwind config:

// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
// ... other colors
},
},
},
}

Conditional Styling

You can use theme variables directly in your components:

<div className="bg-background text-foreground border-border">
This element uses theme colors
</div>

For dark mode specific styling, you can use Tailwind's dark: modifier:

<div className="bg-white dark:bg-slate-950 text-black dark:text-white">
This text changes color in dark mode
</div>

For custom theme-specific styling, you can use CSS selectors:

.modern .special-element {
/* Modern theme specific styles */
background: linear-gradient(to right, hsl(var(--primary)), hsl(var(--chart-2)));
}
/* Apply custom styles to elements based on theme variables */
.special-element {
background: linear-gradient(to right, hsl(var(--primary)), hsl(var(--chart-1)));
}

Theme Customizer

Blueprint UI includes a powerful Theme Customizer that allows you to modify theme variables in real-time. The customizer provides a visual interface for adjusting:

  • Color Variables - Customize all color tokens including primary, secondary, accent colors
  • Typography Variables - Adjust font sizes, weights, and line heights for headings and body text
  • Theme Presets - Switch between light, dark, and modern theme presets

To access the Theme Customizer, click the theme icon in the navigation bar. Changes made in the customizer are applied in real-time and can be saved or exported for use in your projects.

Exporting Theme Variables

After customizing your theme, you can export the variables for use in other projects. The Theme Customizer provides three export options:

  • Export All - Downloads a complete theme.css file with both color and typography variables
  • Export Colors Only - Downloads a colors.css file with just the color variables
  • Export Typography Only - Downloads a typography.css file with just the typography variables

To export your theme variables:

  1. Open the Theme Customizer
  2. Make your desired customizations
  3. Click the "Export" dropdown button
  4. Select your preferred export option
  5. The CSS file will be downloaded to your device

The exported CSS files use CSS variables that can be included in any web project. Simply link the CSS file in your HTML or import it into your stylesheet.

<!-- Include your exported theme CSS -->
<link rel="stylesheet" href="path/to/theme.css">
<!-- Or import in your CSS/SCSS -->
@import 'path/to/theme.css';

Section-Level Theming

The Blueprint UI Library supports section-level theming, allowing you to override the global theme for specific sections. This feature enables more creative designs where different sections of your page can have distinct visual styles, regardless of the user's theme preference.

To apply a theme to a section, simply pass the theme prop with a value of "light","dark", or "modern":

// Hero section with explicit dark theme
<Hero1
theme="dark"
heading="Dark Theme Section"
subtitle="This section always uses dark theme"
/>
// Features section with explicit light theme
<Features
theme="light"
heading="Light Theme Section"
description="This section always uses light theme"
/>
// Section with no theme prop (uses global theme)
<Cta
heading="Global Theme Section"
description="This section adapts to the user's preferred theme"
/>

How Section Themes Work

Section-level theming is implemented through:

  1. A ThemeSection wrapper component that sets CSS variables for the contained section
  2. CSS classes in globals.css that define theme variables for each theme
  3. A theme prop on section components that can override the global theme

The implementation uses CSS variables and a context-based approach:

// theme-section.jsx
'use client';
import React, { createContext, useContext } from 'react';
import PropTypes from 'prop-types';
import { useTheme } from 'next-themes';
// Create context to hold theme override
const ThemeSectionContext = createContext(null);
/**
* Hook to access section theme
* @returns {Object} The section theme context
*/
export const useSectionTheme = () => {
return useContext(ThemeSectionContext);
};
/**
* ThemeSection component that allows setting a specific theme at the section level
* Falls back to global theme if no theme is specified
*/
const ThemeSection = ({
children,
theme = null,
className = '',
}) => {
const { theme: globalTheme } = useTheme();
// If no section theme is specified, use the global theme
const effectiveTheme = theme || globalTheme;
return (
<ThemeSectionContext.Provider value={{ sectionTheme: effectiveTheme }}>
<div
className={`section-theme-${effectiveTheme} ${className}`}
data-section-theme={effectiveTheme}
>
{children}
</div>
</ThemeSectionContext.Provider>
);
};
export default ThemeSection;

The CSS for section-level theming is defined in globals.css:

/* Section-level theme overrides in globals.css */
.section-theme-dark {
--background: 225 15% 8%;
--foreground: 220 10% 92%;
--primary: 220 10% 80%;
/* Additional variables... */
}
.section-theme-light {
--background: 0 0% 100%;
--foreground: 0 0% 12%;
--primary: 220 14% 24%;
/* Additional variables... */
}
.section-theme-modern {
--background: 220 20% 97%;
--foreground: 220 20% 15%;
--primary: 220 70% 50%;
/* Additional variables... */
}

Section Theme Examples

Below are examples of different section theme settings:

Global Theme (inherits from page)

USING GLOBAL THEME

Global Theme Example

This section inherits the theme from the global settings

Image 4
Image 2
Image 3
Image 1
Image 4
Image 2
Image 3
Image 1

Whenweengagewithaclient,webringtogetherourexperienceworkingacrossbrandstrategy,communications,policyanddigitaltoofferaunifiedperspective.Weworkasanextensionofyourteamtoquicklyidentifywhat’sholdingyourbusinessback,designasolution,andbringtogetherthetalentandtoolstodeliverresults.

Dark Theme (explicitly set)

USING DARK THEME

Dark Theme Example

This section always uses dark theme regardless of global setting

Image 4
Image 2
Image 3
Image 1
Image 4
Image 2
Image 3
Image 1

Whenweengagewithaclient,webringtogetherourexperienceworkingacrossbrandstrategy,communications,policyanddigitaltoofferaunifiedperspective.Weworkasanextensionofyourteamtoquicklyidentifywhat’sholdingyourbusinessback,designasolution,andbringtogetherthetalentandtoolstodeliverresults.

Modern Theme (explicitly set)

USING MODERN THEME

Modern Theme Example

This section always uses modern theme regardless of global setting

Image 4
Image 2
Image 3
Image 1
Image 4
Image 2
Image 3
Image 1

Whenweengagewithaclient,webringtogetherourexperienceworkingacrossbrandstrategy,communications,policyanddigitaltoofferaunifiedperspective.Weworkasanextensionofyourteamtoquicklyidentifywhat’sholdingyourbusinessback,designasolution,andbringtogetherthetalentandtoolstodeliverresults.