Theme - Flowbite React

Learn how to customize the appearance of Flowbite React components using the theming system

Flowbite React provides a flexible theming system that allows you to customize the appearance of components. The system is built on top of Tailwind CSS and supports multiple levels of customization.

Component-Level Customization#

The simplest way to customize a component is by using the className prop, which allows you to override or extend the default styles:

import { Button } from "flowbite-react";

function App() {
  return <Button className="bg-red-500 hover:bg-red-600">Custom Button</Button>;
}

Theme Provider#

For application-wide customization, use the ThemeProvider component. The createTheme helper provides TypeScript and Tailwind CSS IntelliSense support:

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const customTheme = createTheme({
  button: {
    color: {
      primary: "bg-red-500 hover:bg-red-600",
      secondary: "bg-blue-500 hover:bg-blue-600",
    },
    size: {
      lg: "px-6 py-3 text-lg",
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={customTheme}>
      <Button color="primary">Red Button</Button>
      <Button color="secondary" size="lg">
        Large Blue Button
      </Button>
    </ThemeProvider>
  );
}

Theme Resolution and Inheritance#

The theming system follows this resolution order:

  1. Component-specific clearTheme prop
  2. Component-specific theme prop
  3. Nearest parent ThemeProvider theme
  4. Default component theme

When using nested ThemeProvider components, the following rules apply:

Unless root={true} is specified:

  • Child providers inherit and merge all theme values from their parent
  • They only override the specific values they define
  • Parent values for undefined properties are preserved

When root={true} is specified:

  • The theme provider ignores all parent theme values
  • No merging occurs with parent themes
  • Only the specified theme and default theme values are used
  • This affects all theme-related props (theme, clearTheme, applyTheme) and component props

Nested Themes#

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const mainTheme = createTheme({
  button: {
    color: {
      primary: "bg-blue-500 hover:bg-blue-600",
    },
    size: {
      lg: "px-6 py-3",
    },
  },
});

const sectionTheme = createTheme({
  button: {
    color: {
      primary: "bg-green-500 hover:bg-green-600",
      // size.lg from mainTheme is preserved
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={mainTheme}>
      <Button size="lg">Blue Large Button</Button>
      <ThemeProvider theme={sectionTheme}>
        {/* Inherits size.lg from mainTheme */}
        <Button size="lg">Green Large Button</Button>
      </ThemeProvider>
    </ThemeProvider>
  );
}

Preventing Theme Inheritance#

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const mainTheme = createTheme({
  button: {
    color: {
      primary: "bg-blue-500 hover:bg-blue-600",
    },
    size: {
      lg: "px-6 py-3",
    },
  },
});

const isolatedTheme = createTheme({
  button: {
    color: {
      primary: "bg-green-500 hover:bg-green-600",
    },
    // No size definitions
  },
});

function App() {
  return (
    <ThemeProvider theme={mainTheme}>
      <Button size="lg">Large Blue Button</Button>

      {/* root={true} prevents merging with mainTheme */}
      <ThemeProvider theme={isolatedTheme} root>
        <Button size="lg">
          {/* size="lg" will use default theme since isolatedTheme
              doesn't define sizes and parent theme is ignored */}
        </Button>
      </ThemeProvider>
    </ThemeProvider>
  );
}

Theme Merging Strategy#

The theme system uses the following merging strategy:

  1. Props Merging: Component props from parent and child ThemeProviders are deep merged
  2. Theme Merging: Theme values are merged using tailwind-merge for intelligent Tailwind CSS class handling
  3. Clear Theme Merging: clearTheme values are deep merged between providers
  4. Apply Theme Merging: applyTheme configurations are deep merged between providers

The use of tailwind-merge ensures:

  • Automatic conflict resolution between Tailwind CSS classes
  • Support for both Tailwind CSS v3 and v4 (automatically detected)
  • Proper handling of complex class combinations
  • Efficient merging without duplicate utilities

For example:

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const baseTheme = createTheme({
  button: {
    base: "rounded-lg shadow-md",
    color: {
      primary: "bg-blue-500 text-white",
    },
  },
});

const customTheme = createTheme({
  button: {
    base: "border-2",
    color: {
      primary: "bg-red-500",
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={baseTheme}>
      {/* Merges themes: rounded-lg shadow-md border-2 */}
      <Button theme={customTheme.button}>Merged Styles</Button>

      {/* Replaces base completely: only border-2 remains */}
      <Button theme={customTheme.button} applyTheme={{ base: "replace" }}>
        Replaced Base Style
      </Button>

      {/* Replaces color completely: loses text-white */}
      <Button theme={customTheme.button} applyTheme={{ color: { primary: "replace" } }}>
        Replaced Color
      </Button>
    </ThemeProvider>
  );
}

Theme Modification Tools#

The combination of theme, clearTheme, and applyTheme props provides granular control over component styling. Here are examples showing different levels of customization:

Component Level Control#

import { Card, createTheme } from "flowbite-react";

const cardTheme = createTheme({
  card: {
    root: {
      base: "rounded-xl bg-white shadow-md",
      children: "space-y-4 p-6",
    },
    img: {
      base: "rounded-t-xl",
      horizontal: "h-full w-full rounded-l-xl",
    },
  },
});

function App() {
  return (
    <>
      {/* Basic theme override */}
      <Card theme={cardTheme.card}>Basic Theme Override</Card>

      {/* Clear specific nested properties */}
      <Card
        theme={cardTheme.card}
        clearTheme={{
          root: { children: true }, // Clear only padding and spacing
          img: { horizontal: true }, // Clear horizontal image styles
        }}
      >
        Selective Clearing
      </Card>

      {/* Control how new styles are applied */}
      <Card
        theme={cardTheme.card}
        applyTheme={{
          root: { base: "replace" }, // Replace entire base styles
          img: { base: "merge" }, // Merge with existing image styles
        }}
      >
        Controlled Style Application
      </Card>

      {/* Combining all three props */}
      <Card theme={cardTheme.card} clearTheme={{ root: { children: true } }} applyTheme={{ img: { base: "replace" } }}>
        Complex Style Control
      </Card>
    </>
  );
}

Nested Component Control#

import { createTheme, Navbar, NavbarCollapse, NavbarLink, ThemeProvider } from "flowbite-react";

const navTheme = createTheme({
  navbar: {
    root: {
      base: "bg-white shadow-lg",
    },
    collapse: {
      base: "w-full md:block md:w-auto",
      list: "mt-4 flex flex-col md:mt-0 md:flex-row md:space-x-8",
    },
    link: {
      base: "block px-3 py-2",
      active: {
        on: "text-blue-600",
        off: "text-gray-900",
      },
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={navTheme}>
      <Navbar>
        {/* Control collapse styles */}
        <NavbarCollapse
          clearTheme={{ list: true }} // Remove default list styles
          applyTheme={{ base: "replace" }} // Replace base styles
        >
          {/* Control individual link styles */}
          <NavbarLink
            href="#"
            active
            theme={{
              base: "font-medium",
              active: {
                on: "text-green-600", // Override active state
              },
            }}
            applyTheme={{
              active: { on: "merge" }, // Merge active state styles
            }}
          >
            Custom Link
          </NavbarLink>
        </NavbarCollapse>
      </Navbar>
    </ThemeProvider>
  );
}

Form Components Control#

import { createTheme, Label, TextInput } from "flowbite-react";

const formTheme = createTheme({
  label: {
    root: {
      base: "text-sm font-medium",
      disabled: "opacity-50",
      colors: {
        default: "text-gray-900",
        error: "text-red-700",
      },
    },
  },
  textInput: {
    base: "block w-full",
    field: {
      base: "rounded-lg border",
      input: {
        base: "px-3 py-2",
        sizes: {
          sm: "text-sm",
          md: "text-base",
        },
        colors: {
          gray: "border-gray-300 bg-gray-50",
          error: "border-red-500 bg-red-50",
        },
      },
    },
  },
});

function App() {
  return (
    <form>
      {/* Label with error state */}
      <Label
        theme={formTheme.label}
        color="error"
        clearTheme={{
          root: { disabled: true }, // Remove disabled styles
        }}
      >
        Email
      </Label>

      {/* Input with custom styling */}
      <TextInput
        theme={formTheme.textInput}
        color="error"
        size="sm"
        applyTheme={{
          field: {
            input: {
              colors: { error: "replace" }, // Replace error styles
              sizes: { sm: "merge" }, // Merge size styles
            },
          },
        }}
      />

      {/* Combining multiple controls */}
      <TextInput
        theme={formTheme.textInput}
        clearTheme={{
          field: {
            input: { sizes: true }, // Remove all size variations
          },
        }}
        applyTheme={{
          base: "merge", // Merge base styles
          field: { base: "replace" }, // Replace field base styles
        }}
      />
    </form>
  );
}

These examples demonstrate how to:

  • Use nested theme properties for precise control
  • Clear specific style categories while preserving others
  • Control how new styles are merged or replaced
  • Combine multiple theme controls for complex customization
  • Handle component-specific theme variations
  • Manage state-dependent styles (active, disabled, etc.)

Clearing Theme Values#

The clearTheme prop allows you to selectively or completely remove theme values, reverting them to their default styles. When a theme value is cleared, it's set to an empty string.

Basic Usage#

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const theme = createTheme({
  button: {
    color: {
      primary: "bg-red-500 hover:bg-red-600",
    },
    base: "rounded-lg",
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Button>Red Rounded Button</Button>
      {/* Clear specific theme property */}
      <Button clearTheme={{ color: true }}>Default Color, Still Rounded</Button>
      {/* Clear all button theme values */}
      <Button clearTheme>Completely Default Button</Button>
    </ThemeProvider>
  );
}

Selective Clearing#

You can clear specific nested properties while keeping others:

import { Card, createTheme, ThemeProvider } from "flowbite-react";

const theme = createTheme({
  card: {
    root: {
      base: "rounded-xl shadow-lg",
      children: "space-y-4 p-6",
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Card>Regular Card</Card>
      <Card clearTheme={{ root: { children: true } }}>
        {/* Keeps rounded-xl and shadow-lg, but clears padding and spacing */}
      </Card>
    </ThemeProvider>
  );
}

Applying Theme Values#

The applyTheme prop provides fine-grained control over how theme values are merged. It supports two modes:

  • "merge" (default): Combines the new theme values with existing ones
  • "replace": Completely replaces existing theme values

Merging vs Replacing#

import { Button, createTheme, ThemeProvider } from "flowbite-react";

const baseTheme = createTheme({
  button: {
    base: "rounded-lg shadow-md",
    color: {
      primary: "bg-blue-500 text-white",
    },
  },
});

const customTheme = createTheme({
  button: {
    base: "border-2",
    color: {
      primary: "bg-red-500",
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={baseTheme}>
      {/* Merges themes: rounded-lg shadow-md border-2 */}
      <Button theme={customTheme.button}>Merged Styles</Button>

      {/* Replaces base completely: only border-2 remains */}
      <Button theme={customTheme.button} applyTheme={{ base: "replace" }}>
        Replaced Base Style
      </Button>

      {/* Replaces color completely: loses text-white */}
      <Button theme={customTheme.button} applyTheme={{ color: { primary: "replace" } }}>
        Replaced Color
      </Button>
    </ThemeProvider>
  );
}

Inheritance Control#

The applyTheme prop is particularly useful when working with nested components:

import { createTheme, Navbar, NavbarCollapse, NavbarLink, ThemeProvider } from "flowbite-react";

const theme = createTheme({
  navbar: {
    root: {
      base: "bg-white shadow-lg",
    },
    collapse: {
      base: "w-full md:block md:w-auto",
      list: "mt-4 flex flex-col md:mt-0 md:flex-row md:space-x-8",
    },
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Navbar>
        <NavbarCollapse
          applyTheme={{
            list: "replace", // Replace entire list styles
          }}
        >
          <NavbarLink href="#">Custom Layout</NavbarLink>
        </NavbarCollapse>
      </Navbar>
    </ThemeProvider>
  );
}

Theme Resolution Order#

When both clearTheme and applyTheme are used, the resolution follows this order:

  1. Apply clearTheme to remove specified values
  2. Apply component-specific theme prop
  3. Apply applyTheme rules to control how new values are merged
  4. Inherit from parent ThemeProvider (unless root={true})
  5. Fall back to default component theme

This system provides complete control over theme inheritance and application while maintaining a predictable behavior.

Provider-Level Props#

The ThemeProvider component accepts a props prop that allows you to set default props for all components within its scope. These props are merged with any component-specific props, with component props taking precedence:

import { Button, ThemeProvider } from "flowbite-react";

function App() {
  return (
    <ThemeProvider
      props={{
        // Set default props for all buttons
        button: {
          color: "success",
          size: "lg",
        },
      }}
    >
      {/* Will be large and green */}
      <Button>Inherits Provider Props</Button>

      {/* Will be large and red (color prop overrides provider) */}
      <Button color="error">Overrides Color Prop</Button>

      {/* Nested providers merge props by default */}
      <ThemeProvider
        props={{
          button: {
            size: "sm", // Override size while keeping color from parent
          },
        }}
      >
        {/* Will be small and green */}
        <Button>Inherits Merged Props</Button>
      </ThemeProvider>

      {/* root={true} prevents props inheritance */}
      <ThemeProvider
        root
        props={{
          button: {
            size: "sm",
          },
        }}
      >
        {/* Will be small with default color */}
        <Button>Independent Props</Button>
      </ThemeProvider>
    </ThemeProvider>
  );
}

Props are resolved in the following order:

  1. Component-specific props
  2. Nearest parent ThemeProvider props
  3. Default component props

Like themes, provider props are deep merged between parent and child providers unless root={true} is specified.

Component-Specific Theme#

You can also apply a custom theme to a specific component instance using the theme prop:

import { Button, createTheme } from "flowbite-react";

const buttonTheme = createTheme({
  button: {
    color: {
      custom: "bg-purple-500 text-white hover:bg-purple-600",
    },
  },
}).button;

function App() {
  return (
    <Button theme={buttonTheme} color="custom">
      Purple Button
    </Button>
  );
}

Type Safety and IntelliSense#

The createTheme helper ensures type safety and enables Tailwind CSS IntelliSense in your IDE:

import { createTheme } from "flowbite-react";

// Full theme customization
const theme = createTheme({
  button: {
    color: {
      primary: "bg-blue-500 hover:bg-blue-600", // ✓ Tailwind CSS IntelliSense
      custom: 123, // ✗ Type error: expected string
    },
  },
});

// Single component theme
const buttonTheme = createTheme({
  button: {
    size: {
      xl: "px-8 py-4 text-xl", // ✓ Tailwind CSS IntelliSense
    },
  },
}).button;

This helps catch errors early and provides better development experience with auto-completion for Tailwind CSS classes.

For information on how to create your own themeable components that work with this system, see the Creating Custom Components guide.