We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide26 min read

Flowbite, UI components built on Tailwind CSS

Flowbite provides Tailwind CSS components and blocks across many frameworks. Version 4, Tailwind v4, the free and paid tiers, and accessibility.

Flowbite, UI components built on Tailwind CSS

Flowbite is a set of interface components built on Tailwind CSS, available in several forms: as markup you copy, as a package carrying a JavaScript layer, and as libraries for individual frameworks. The core is MIT licensed at version 4.0.2, with a separately sold tier of ready made blocks and templates.

Two different ways to use it, easily confused

This distinction determines what to expect and tends to get blurred in material about this library.

The first variant is plain Tailwind. You copy markup with classes and get a finished element: a card, a form, a table. Nothing is installed, there are no dependencies, and the code is yours from the moment you paste it. That works for everything not requiring interaction.

The second variant is needed wherever something has to open, close, or respond to a keyboard. A dropdown, a modal dialog, a date picker, a carousel. Here a JavaScript layer is required, which you either add as a package driving markup through attributes or take as components for your framework.

The practical consequence surprises people on a first attempt. Copying modal markup from the project site and pasting it into an application without installing the JavaScript layer produces an element that looks right and does nothing. That is not a bug but the result of picking the first variant where the second was needed.

It is also worth knowing that the React variant follows somewhat different rules from the rest. It carries its own version number, its own release cadence, and its own solutions, including a mechanism generating the required classes automatically. The core package version therefore says nothing about which version the React library is at.

Tailwind version 4 and what it changes

This is the most common source of trouble during setup, because it concerns configuration rather than the components themselves.

Tailwind version 4 moved configuration out of a JavaScript file and into a stylesheet. Instead of a settings object you now write directives in CSS: importing modules, declaring theme variables, pointing at files to scan. Every tutorial describing adding a plugin to a configuration file refers to version 3 and will not work in a new project.

Flowbite supports both versions, which is convenient but requires choosing a path deliberately. Check which Tailwind version your project uses before copying instructions from the web, because the symptom of getting it wrong is styles simply not applying, with no error message.

Class scanning is a separate matter. Tailwind generates only the classes it finds in source files, so classes coming from a package inside your dependencies directory have to be covered by scanning. Skipping that step yields unstyled components, which across many elements looks like a broken installation and is one missing configuration line. There is more on the mechanism in the Tailwind CSS writeup.

The same mechanism explains another common slip, worth knowing regardless of this library. Classes assembled at run time, by joining name fragments with a variable for instance, will never be generated, because the scanner reads files as text and does not execute code. The symptom is a colour or a spacing that works for one value and stays silent for another. The fix is writing full class names out in the code and choosing between them, rather than building a name from pieces.

Dark mode and themes

Dark mode support is built into the components here, but switching it on requires one decision worth taking deliberately at the start of a project.

The toggle can work two ways: following the operating system setting, or driven by a class on a parent element. The first is simpler and needs no code, the second lets you give the user a switch. In practice most projects want both at once: the system setting by default, with manual override and the choice remembered.

The technical trap concerns the first render. If you read the theme from browser storage after the page loads, the user briefly sees the default variant and then the correct one. That shows up as a flash of light background for somebody who chose the dark theme. The standard remedy is setting the class from a script executed before the page paints, ahead of loading the rest of the application.

When Flowbite is a good choice

The scenarios are worth naming plainly, because this library aims at a specific niche and fares worse than the competition outside it.

It works best where a project does not rest on one framework. An agency building sites in various technologies, a team maintaining an older application alongside a new one, a project where some pages are plain server rendered HTML. The same look and the same way of working across all of those is a real saving no framework bound library can match.

The second good scenario is an admin panel or internal tool. What counts is assembling a working interface from tables, forms, and charts quickly rather than an original appearance. There a set of components sharing a consistent aesthetic wins, because nobody has to make design decisions.

It fares worse on a product meant to stand out visually. The components are recognisable, and a page assembled from them looks like many other pages. It can be restyled, but by then the work involved cancels the head start.

It is also a weaker choice for an application with high accessibility requirements, covered below, and for a team that already has its own design system. In the latter case the imposed class structure and conventions start getting in the way rather than helping.

What is Flowbite?

Flowbite is an open-source component library built on Tailwind CSS, offering over 50 ready-to-use UI components and 450+ page blocks (ready-made page sections). Unlike many libraries, Flowbite is available for virtually every JavaScript framework - React, Vue, Svelte, Angular, as well as vanilla JavaScript and pure HTML.

Flowbite was created with development acceleration in mind - instead of building each component from scratch, you can copy ready-made code or install a package and have a working navbar, modal, or datepicker in minutes. All components are fully responsive, support dark mode, and are optimized for accessibility.

Flowbite's Philosophy

Flowbite offers two approaches:

  1. Copy-paste HTML/CSS - Each component has code to copy that works with pure Tailwind CSS
  2. JavaScript Packages - For interactive components (dropdown, modal, datepicker) you need JS

This makes Flowbite extremely flexible - you can use just a few components or build an entire application on this library.

Flowbite vs other libraries

FeatureFlowbiteDaisyUITailwind UIshadcn/ui
PriceFree + ProFree$299+Free
FrameworksAllTailwind onlyReactReact
Section Blocks450+None500+~50
FigmaYes (Pro)YesNoNo
Dark modeBuilt-inBuilt-inBuilt-inManual
LicenseMITMITCommercialMIT
JavaScriptOptionalCSS onlyReactReact
TypeScriptFullN/AFullFull

When to choose Flowbite?

Choose Flowbite when:

  • You need support for multiple frameworks
  • You want ready-made blocks (hero, pricing, features)
  • You're looking for a free alternative to Tailwind UI
  • You're building a dashboard or admin panel
  • You need a datepicker, carousel, drawer

Consider alternatives when:

  • You need CSS only without JS (DaisyUI)
  • You want full control over code (shadcn/ui)
  • Budget allows for a paid solution (Tailwind UI)

Installation

Vanilla JavaScript / HTML

Before the commands, one note on the shape of the configuration. The blocks below show the JavaScript file arrangement, which applies to Tailwind version three. In version four, described in the previous section, the same thing is written as directives in a stylesheet.

Code
CSS
@import "flowbite/src/themes/default";
@plugin "flowbite/plugin";
@source "../node_modules/flowbite";

The three lines correspond to the three things the configuration file did in the older arrangement: pulling in a theme, attaching the plugin, and naming the directory to scan for classes. There are several themes and you pick one, with the name in the first line deciding which.

Code
Bash
# npm
npm install flowbite

# yarn
yarn add flowbite

# pnpm
pnpm add flowbite
JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  content: [
    "./node_modules/flowbite/**/*.js"
  ],
  plugins: [
    require('flowbite/plugin')
  ]
}
Code
HTML
<!-- Add script before </body> -->
<script src="../path/to/flowbite/dist/flowbite.min.js"></script>

<!-- Or from CDN -->
<script src="https://cdn.jsdelivr.net/npm/flowbite@4.0.2/dist/flowbite.min.js"></script>

React

Code
Bash
npm install flowbite flowbite-react
JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  content: [
    './node_modules/flowbite-react/lib/**/*.js',
  ],
  plugins: [
    require('flowbite/plugin')
  ],
}

Vue 3

Code
Bash
npm install flowbite flowbite-vue
JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  content: [
    './node_modules/flowbite-vue/**/*.{js,jsx,ts,tsx}',
    './node_modules/flowbite/**/*.js'
  ],
  plugins: [
    require('flowbite/plugin')
  ],
}

Svelte

Code
Bash
npm install flowbite flowbite-svelte
JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  content: [
    './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}'
  ],
  plugins: [
    require('flowbite/plugin')
  ],
}

Angular

Code
Bash
npm install flowbite
JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  content: [
    "./node_modules/flowbite/**/*.js"
  ],
  plugins: [
    require('flowbite/plugin')
  ]
}
angular.json
JSON
// angular.json - add script
"scripts": [
  "node_modules/flowbite/dist/flowbite.min.js"
]

React components

Alert

Code
TypeScript
import { Alert } from 'flowbite-react'
import { HiInformationCircle, HiX } from 'react-icons/hi'

function AlertExamples() {
  return (
    <div className="flex flex-col gap-4">
      {/* Basic */}
      <Alert color="info">
        <span className="font-medium">Info alert!</span> Change a few things up and try submitting again.
      </Alert>

      {/* Different colors */}
      <Alert color="failure">
        <span className="font-medium">Danger alert!</span> Something went wrong.
      </Alert>

      <Alert color="success">
        <span className="font-medium">Success alert!</span> Your purchase is complete.
      </Alert>

      <Alert color="warning">
        <span className="font-medium">Warning alert!</span> Please check your input.
      </Alert>

      {/* With icon */}
      <Alert color="info" icon={HiInformationCircle}>
        <span className="font-medium">Info!</span> This is an informational alert.
      </Alert>

      {/* With dismiss button */}
      <Alert
        color="success"
        onDismiss={() => console.log('Alert dismissed!')}
      >
        <span className="font-medium">Success!</span> You can dismiss this alert.
      </Alert>

      {/* With border */}
      <Alert color="info" withBorderAccent>
        <span className="font-medium">Info!</span> Alert with border accent.
      </Alert>

      {/* With additional content */}
      <Alert
        color="info"
        additionalContent={
          <div className="mt-2 mb-4 text-sm text-cyan-700 dark:text-cyan-800">
            More info about this alert goes here. This example text is going to run a bit longer
            so that you can see how spacing works.
          </div>
        }
        icon={HiInformationCircle}
      >
        <span className="font-medium">More information</span>
      </Alert>

      {/* Rounded */}
      <Alert color="info" rounded>
        Rounded alert!
      </Alert>
    </div>
  )
}

Navbar

Code
TypeScript
import { Avatar, Button, Dropdown, DropdownDivider, DropdownHeader, DropdownItem, Navbar, NavbarBrand, NavbarCollapse, NavbarLink, NavbarToggle } from 'flowbite-react'

function NavbarExample() {
  return (
    <Navbar fluid rounded>
      <NavbarBrand href="https://flowbite.com/">
        <img
          src="/logo.svg"
          className="mr-3 h-6 sm:h-9"
          alt="Flowbite Logo"
        />
        <span className="self-center whitespace-nowrap text-xl font-semibold dark:text-white">
          Flowbite
        </span>
      </NavbarBrand>

      <div className="flex md:order-2">
        <Button>Get started</Button>
        <NavbarToggle />
      </div>

      <NavbarCollapse>
        <NavbarLink href="/" active>
          Home
        </NavbarLink>
        <NavbarLink href="/about">About</NavbarLink>
        <NavbarLink href="/services">Services</NavbarLink>
        <NavbarLink href="/pricing">Pricing</NavbarLink>
        <NavbarLink href="/contact">Contact</NavbarLink>
      </NavbarCollapse>
    </Navbar>
  )
}

// With dropdown

function NavbarWithDropdown() {
  return (
    <Navbar fluid rounded>
      <NavbarBrand href="/">
        <span className="self-center whitespace-nowrap text-xl font-semibold dark:text-white">
          Brand
        </span>
      </NavbarBrand>

      <div className="flex md:order-2">
        <Dropdown
          arrowIcon={false}
          inline
          label={
            <Avatar
              alt="User settings"
              img="/avatar.png"
              rounded
            />
          }
        >
          <DropdownHeader>
            <span className="block text-sm">John Doe</span>
            <span className="block truncate text-sm font-medium">
              john@example.com
            </span>
          </DropdownHeader>
          <DropdownItem>Dashboard</DropdownItem>
          <DropdownItem>Settings</DropdownItem>
          <DropdownDivider />
          <DropdownItem>Sign out</DropdownItem>
        </Dropdown>
        <NavbarToggle />
      </div>

      <NavbarCollapse>
        <NavbarLink href="/" active>Home</NavbarLink>
        <NavbarLink href="/about">About</NavbarLink>
        <NavbarLink href="/services">Services</NavbarLink>
      </NavbarCollapse>
    </Navbar>
  )
}

Modal

Code
TypeScript
import { useState } from 'react'
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'flowbite-react'
import { HiOutlineExclamationCircle } from 'react-icons/hi'

function ModalExample() {
  const [openModal, setOpenModal] = useState(false)

  return (
    <>
      <Button onClick={() => setOpenModal(true)}>Open modal</Button>

      <Modal show={openModal} onClose={() => setOpenModal(false)}>
        <ModalHeader>Terms of Service</ModalHeader>
        <ModalBody>
          <div className="space-y-6">
            <p className="text-base leading-relaxed text-gray-500 dark:text-gray-400">
              With less than a month to go before the European Union enacts new consumer privacy laws
              for its citizens, companies around the world are updating their terms of service.
            </p>
            <p className="text-base leading-relaxed text-gray-500 dark:text-gray-400">
              The European Union's General Data Protection Regulation (G.D.P.R.) goes into effect on
              May 25 and is meant to ensure a common set of data rights.
            </p>
          </div>
        </ModalBody>
        <ModalFooter>
          <Button onClick={() => setOpenModal(false)}>I accept</Button>
          <Button color="gray" onClick={() => setOpenModal(false)}>
            Decline
          </Button>
        </ModalFooter>
      </Modal>
    </>
  )
}

// Confirmation Modal
function DeleteConfirmModal() {
  const [openModal, setOpenModal] = useState(false)

  return (
    <>
      <Button color="failure" onClick={() => setOpenModal(true)}>
        Delete account
      </Button>

      <Modal show={openModal} size="md" onClose={() => setOpenModal(false)} popup>
        <ModalHeader />
        <ModalBody>
          <div className="text-center">
            <HiOutlineExclamationCircle className="mx-auto mb-4 h-14 w-14 text-gray-400 dark:text-gray-200" />
            <h3 className="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">
              Are you sure you want to delete this product?
            </h3>
            <div className="flex justify-center gap-4">
              <Button color="failure" onClick={() => setOpenModal(false)}>
                Yes, I'm sure
              </Button>
              <Button color="gray" onClick={() => setOpenModal(false)}>
                No, cancel
              </Button>
            </div>
          </div>
        </ModalBody>
      </Modal>
    </>
  )
}

// Different sizes
function SizedModals() {
  const [size, setSize] = useState('md')
  const [openModal, setOpenModal] = useState(false)

  return (
    <>
      <div className="flex flex-wrap gap-4">
        {['sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl'].map((s) => (
          <Button
            key={s}
            onClick={() => {
              setSize(s)
              setOpenModal(true)
            }}
          >
            {s}
          </Button>
        ))}
      </div>

      <Modal show={openModal} size={size} onClose={() => setOpenModal(false)}>
        <ModalHeader>Modal {size}</ModalHeader>
        <ModalBody>
          <p>This is a {size} modal.</p>
        </ModalBody>
      </Modal>
    </>
  )
}

Carousel

Code
TypeScript
import { Carousel } from 'flowbite-react'

function CarouselExample() {
  return (
    <div className="h-56 sm:h-64 xl:h-80 2xl:h-96">
      <Carousel>
        <img src="/carousel-1.svg" alt="Slide 1" />
        <img src="/carousel-2.svg" alt="Slide 2" />
        <img src="/carousel-3.svg" alt="Slide 3" />
        <img src="/carousel-4.svg" alt="Slide 4" />
        <img src="/carousel-5.svg" alt="Slide 5" />
      </Carousel>
    </div>
  )
}

// Without controls
function CarouselWithoutControls() {
  return (
    <div className="h-56 sm:h-64 xl:h-80 2xl:h-96">
      <Carousel slide={false}>
        <img src="/carousel-1.svg" alt="Slide 1" />
        <img src="/carousel-2.svg" alt="Slide 2" />
        <img src="/carousel-3.svg" alt="Slide 3" />
      </Carousel>
    </div>
  )
}

// With custom indicators
function CarouselCustomIndicators() {
  return (
    <div className="h-56 sm:h-64 xl:h-80 2xl:h-96">
      <Carousel
        indicators={false}
        leftControl={
          <span className="group-hover:bg-white/50 group-focus:outline-none group-focus:ring-4 group-focus:ring-white">
          </span>
        }
        rightControl={
          <span className="group-hover:bg-white/50 group-focus:outline-none group-focus:ring-4 group-focus:ring-white">
          </span>
        }
      >
        <img src="/carousel-1.svg" alt="Slide 1" />
        <img src="/carousel-2.svg" alt="Slide 2" />
      </Carousel>
    </div>
  )
}

// Auto-slide
function AutoSlideCarousel() {
  return (
    <div className="h-56 sm:h-64 xl:h-80 2xl:h-96">
      <Carousel slideInterval={3000}>
        <img src="/carousel-1.svg" alt="Slide 1" />
        <img src="/carousel-2.svg" alt="Slide 2" />
        <img src="/carousel-3.svg" alt="Slide 3" />
      </Carousel>
    </div>
  )
}

Sidebar

Code
TypeScript
import { Sidebar, SidebarCollapse, SidebarItem, SidebarItemGroup, SidebarItems, SidebarLogo } from 'flowbite-react'
import {
  HiArrowSmRight,
  HiChartPie,
  HiInbox,
  HiShoppingBag,
  HiTable,
  HiUser,
} from 'react-icons/hi'

function SidebarExample() {
  return (
    <Sidebar aria-label="Default sidebar example">
      <SidebarItems>
        <SidebarItemGroup>
          <SidebarItem href="#" icon={HiChartPie}>
            Dashboard
          </SidebarItem>
          <SidebarItem href="#" icon={HiInbox} label="3">
            Inbox
          </SidebarItem>
          <SidebarItem href="#" icon={HiUser}>
            Users
          </SidebarItem>
          <SidebarItem href="#" icon={HiShoppingBag}>
            Products
          </SidebarItem>
          <SidebarItem href="#" icon={HiArrowSmRight}>
            Sign In
          </SidebarItem>
          <SidebarItem href="#" icon={HiTable}>
            Sign Up
          </SidebarItem>
        </SidebarItemGroup>
      </SidebarItems>
    </Sidebar>
  )
}

// With collapse (submenu)
function SidebarWithCollapse() {
  return (
    <Sidebar aria-label="Sidebar with multi-level dropdown">
      <SidebarItems>
        <SidebarItemGroup>
          <SidebarItem href="#" icon={HiChartPie}>
            Dashboard
          </SidebarItem>
          <SidebarCollapse icon={HiShoppingBag} label="E-commerce">
            <SidebarItem href="#">Products</SidebarItem>
            <SidebarItem href="#">Billing</SidebarItem>
            <SidebarItem href="#">Invoice</SidebarItem>
          </SidebarCollapse>
          <SidebarItem href="#" icon={HiInbox}>
            Inbox
          </SidebarItem>
          <SidebarItem href="#" icon={HiUser}>
            Users
          </SidebarItem>
        </SidebarItemGroup>
      </SidebarItems>
    </Sidebar>
  )
}

// With logo
function SidebarWithLogo() {
  return (
    <Sidebar aria-label="Sidebar with logo">
      <SidebarLogo href="#" img="/logo.svg" imgAlt="Flowbite logo">
        Flowbite
      </SidebarLogo>
      <SidebarItems>
        <SidebarItemGroup>
          <SidebarItem href="#" icon={HiChartPie}>
            Dashboard
          </SidebarItem>
          <SidebarItem href="#" icon={HiUser}>
            Users
          </SidebarItem>
        </SidebarItemGroup>
      </SidebarItems>
    </Sidebar>
  )
}

Drawer (Offcanvas)

Code
TypeScript
import { useState } from 'react'
import { Button, Drawer, DrawerHeader, DrawerItems } from 'flowbite-react'

function DrawerExample() {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open drawer</Button>

      <Drawer open={isOpen} onClose={() => setIsOpen(false)}>
        <DrawerHeader title="Drawer" />
        <DrawerItems>
          <p className="mb-6 text-sm text-gray-500 dark:text-gray-400">
            Supercharge your hiring by taking advantage of our limited-time sale.
          </p>
          <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
            <Button>Learn more</Button>
            <Button color="gray" outline>
              Get access
            </Button>
          </div>
        </DrawerItems>
      </Drawer>
    </>
  )
}

// Drawer from different positions
function DrawerPositions() {
  const [leftOpen, setLeftOpen] = useState(false)
  const [rightOpen, setRightOpen] = useState(false)
  const [topOpen, setTopOpen] = useState(false)
  const [bottomOpen, setBottomOpen] = useState(false)

  return (
    <div className="flex gap-4">
      <Button onClick={() => setLeftOpen(true)}>Left</Button>
      <Drawer open={leftOpen} onClose={() => setLeftOpen(false)} position="left">
        <DrawerHeader title="Left Drawer" />
        <DrawerItems>
          <p>Content from the left</p>
        </DrawerItems>
      </Drawer>

      <Button onClick={() => setRightOpen(true)}>Right</Button>
      <Drawer open={rightOpen} onClose={() => setRightOpen(false)} position="right">
        <DrawerHeader title="Right Drawer" />
        <DrawerItems>
          <p>Content from the right</p>
        </DrawerItems>
      </Drawer>

      <Button onClick={() => setTopOpen(true)}>Top</Button>
      <Drawer open={topOpen} onClose={() => setTopOpen(false)} position="top">
        <DrawerHeader title="Top Drawer" />
        <DrawerItems>
          <p>Content from the top</p>
        </DrawerItems>
      </Drawer>

      <Button onClick={() => setBottomOpen(true)}>Bottom</Button>
      <Drawer open={bottomOpen} onClose={() => setBottomOpen(false)} position="bottom">
        <DrawerHeader title="Bottom Drawer" />
        <DrawerItems>
          <p>Content from the bottom</p>
        </DrawerItems>
      </Drawer>
    </div>
  )
}

Datepicker

Code
TypeScript
import { Datepicker } from 'flowbite-react'

function DatepickerExamples() {
  return (
    <div className="flex flex-col gap-4">
      {/* Basic */}
      <Datepicker />

      {/* With default date */}
      <Datepicker defaultValue={new Date(2024, 0, 15)} />

      {/* With min and max date */}
      <Datepicker
        minDate={new Date(2024, 0, 1)}
        maxDate={new Date(2024, 11, 31)}
      />

      {/* Inline */}
      <Datepicker inline />

      {/* With title */}
      <Datepicker title="Select Date" />

      {/* Auto hide */}
      <Datepicker autoHide={false} />

      {/* Controlled */}
      <Datepicker
        onChange={(date) => console.log(date)}
      />

      {/* With labels */}
      <Datepicker
        showClearButton
        showTodayButton
        labelClearButton="Clear"
        labelTodayButton="Today"
      />

      {/* Different languages */}
      <Datepicker language="en-US" />

      {/* Week starts on Monday */}
      <Datepicker weekStart={1} />
    </div>
  )
}

Dropdown

Code
TypeScript
import { Dropdown, DropdownDivider, DropdownHeader, DropdownItem } from 'flowbite-react'

function DropdownExamples() {
  return (
    <div className="flex gap-4">
      {/* Basic */}
      <Dropdown label="Dropdown">
        <DropdownItem>Dashboard</DropdownItem>
        <DropdownItem>Settings</DropdownItem>
        <DropdownItem>Earnings</DropdownItem>
        <DropdownItem>Sign out</DropdownItem>
      </Dropdown>

      {/* With divider */}
      <Dropdown label="Actions">
        <DropdownItem>Edit</DropdownItem>
        <DropdownItem>Export</DropdownItem>
        <DropdownDivider />
        <DropdownItem>Delete</DropdownItem>
      </Dropdown>

      {/* With header */}
      <Dropdown label="User menu">
        <DropdownHeader>
          <span className="block text-sm">John Doe</span>
          <span className="block truncate text-sm font-medium">
            john@example.com
          </span>
        </DropdownHeader>
        <DropdownItem>Profile</DropdownItem>
        <DropdownItem>Settings</DropdownItem>
        <DropdownDivider />
        <DropdownItem>Sign out</DropdownItem>
      </Dropdown>

      {/* With icons */}
      <Dropdown label="Options">
        <DropdownItem icon={HiViewGrid}>Dashboard</DropdownItem>
        <DropdownItem icon={HiCog}>Settings</DropdownItem>
        <DropdownItem icon={HiCurrencyDollar}>Earnings</DropdownItem>
        <DropdownDivider />
        <DropdownItem icon={HiLogout}>Sign out</DropdownItem>
      </Dropdown>

      {/* Inline (no border) */}
      <Dropdown inline label="Inline dropdown">
        <DropdownItem>Item 1</DropdownItem>
        <DropdownItem>Item 2</DropdownItem>
      </Dropdown>

      {/* Different sizes */}
      <Dropdown label="Small" size="sm">
        <DropdownItem>Item</DropdownItem>
      </Dropdown>

      <Dropdown label="Large" size="lg">
        <DropdownItem>Item</DropdownItem>
      </Dropdown>

      {/* Different placements */}
      <Dropdown label="Top" placement="top">
        <DropdownItem>Opens at top</DropdownItem>
      </Dropdown>

      <Dropdown label="Left" placement="left">
        <DropdownItem>Opens at left</DropdownItem>
      </Dropdown>
    </div>
  )
}

Accordion

Code
TypeScript
import { Accordion, AccordionContent, AccordionPanel, AccordionTitle } from 'flowbite-react'

function AccordionExample() {
  return (
    <Accordion>
      <AccordionPanel>
        <AccordionTitle>What is Flowbite?</AccordionTitle>
        <AccordionContent>
          <p className="mb-2 text-gray-500 dark:text-gray-400">
            Flowbite is an open-source library of interactive components built on top of Tailwind CSS.
          </p>
          <p className="text-gray-500 dark:text-gray-400">
            Check out the{' '}
            <a
              href="https://flowbite.com/docs/getting-started/introduction/"
              className="text-cyan-600 hover:underline dark:text-cyan-500"
            >
              getting started guide
            </a>{' '}
            and start building websites.
          </p>
        </AccordionContent>
      </AccordionPanel>
      <AccordionPanel>
        <AccordionTitle>Is there a Figma file?</AccordionTitle>
        <AccordionContent>
          <p className="mb-2 text-gray-500 dark:text-gray-400">
            Yes! You can get the Figma file in Flowbite Pro.
          </p>
        </AccordionContent>
      </AccordionPanel>
      <AccordionPanel>
        <AccordionTitle>What frameworks are supported?</AccordionTitle>
        <AccordionContent>
          <p className="mb-2 text-gray-500 dark:text-gray-400">
            React, Vue, Svelte, Angular, and vanilla JavaScript.
          </p>
        </AccordionContent>
      </AccordionPanel>
    </Accordion>
  )
}

// Always open (all panels)
function AccordionAlwaysOpen() {
  return (
    <Accordion alwaysOpen>
      <AccordionPanel>
        <AccordionTitle>Panel 1</AccordionTitle>
        <AccordionContent>
          <p>Content 1</p>
        </AccordionContent>
      </AccordionPanel>
      <AccordionPanel>
        <AccordionTitle>Panel 2</AccordionTitle>
        <AccordionContent>
          <p>Content 2</p>
        </AccordionContent>
      </AccordionPanel>
    </Accordion>
  )
}

// Without border
function AccordionFlush() {
  return (
    <Accordion flush>
      <AccordionPanel>
        <AccordionTitle>Panel without borders</AccordionTitle>
        <AccordionContent>
          <p>Cleaner look</p>
        </AccordionContent>
      </AccordionPanel>
    </Accordion>
  )
}

Table

Code
TypeScript
import { Checkbox, Table, TableBody, TableCell, TableHead, TableHeadCell, TableRow } from 'flowbite-react'

function TableExample() {
  return (
    <div className="overflow-x-auto">
      <Table>
        <TableHead>
          <TableHeadCell className="p-4">
            <Checkbox />
          </TableHeadCell>
          <TableHeadCell>Product name</TableHeadCell>
          <TableHeadCell>Color</TableHeadCell>
          <TableHeadCell>Category</TableHeadCell>
          <TableHeadCell>Price</TableHeadCell>
          <TableHeadCell>
            <span className="sr-only">Edit</span>
          </TableHeadCell>
        </TableHead>
        <TableBody className="divide-y">
          <TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
            <TableCell className="p-4">
              <Checkbox />
            </TableCell>
            <TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
              Apple MacBook Pro 17"
            </TableCell>
            <TableCell>Silver</TableCell>
            <TableCell>Laptop</TableCell>
            <TableCell>$2999</TableCell>
            <TableCell>
              <a href="#" className="font-medium text-cyan-600 hover:underline dark:text-cyan-500">
                Edit
              </a>
            </TableCell>
          </TableRow>
          <TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
            <TableCell className="p-4">
              <Checkbox />
            </TableCell>
            <TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
              Microsoft Surface Pro
            </TableCell>
            <TableCell>White</TableCell>
            <TableCell>Laptop PC</TableCell>
            <TableCell>$1999</TableCell>
            <TableCell>
              <a href="#" className="font-medium text-cyan-600 hover:underline dark:text-cyan-500">
                Edit
              </a>
            </TableCell>
          </TableRow>
        </TableBody>
      </Table>
    </div>
  )
}

// Striped
function StripedTable() {
  return (
    <Table striped>
      <TableHead>
        <TableHeadCell>Name</TableHeadCell>
        <TableHeadCell>Email</TableHeadCell>
      </TableHead>
      <TableBody className="divide-y">
        <TableRow>
          <TableCell>John Doe</TableCell>
          <TableCell>john@example.com</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>Jane Smith</TableCell>
          <TableCell>jane@example.com</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  )
}

// Hoverable
function HoverableTable() {
  return (
    <Table hoverable>
      <TableHead>
        <TableHeadCell>Product</TableHeadCell>
        <TableHeadCell>Price</TableHeadCell>
      </TableHead>
      <TableBody className="divide-y">
        <TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
          <TableCell>Product 1</TableCell>
          <TableCell>$99</TableCell>
        </TableRow>
        <TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
          <TableCell>Product 2</TableCell>
          <TableCell>$149</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  )
}

Forms

Code
TypeScript
import { Button, Checkbox, FileInput, Label, Radio, RangeSlider, Select, TextInput, Textarea, ToggleSwitch } from 'flowbite-react'
import { HiMail, HiLockClosed } from 'react-icons/hi'

function FormExamples() {
  return (
    <form className="flex max-w-md flex-col gap-4">
      {/* Text Input */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="email" value="Your email" />
        </div>
        <TextInput
          id="email"
          type="email"
          placeholder="name@flowbite.com"
          required
          icon={HiMail}
        />
      </div>

      {/* Password */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="password" value="Your password" />
        </div>
        <TextInput
          id="password"
          type="password"
          required
          icon={HiLockClosed}
        />
      </div>

      {/* Input sizes */}
      <TextInput sizing="sm" placeholder="Small" />
      <TextInput sizing="md" placeholder="Medium (default)" />
      <TextInput sizing="lg" placeholder="Large" />

      {/* Textarea */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="comment" value="Your message" />
        </div>
        <Textarea
          id="comment"
          placeholder="Leave a comment..."
          rows={4}
        />
      </div>

      {/* Select */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="countries" value="Select your country" />
        </div>
        <Select id="countries" required>
          <option>United States</option>
          <option>Canada</option>
          <option>France</option>
          <option>Germany</option>
        </Select>
      </div>

      {/* Checkbox */}
      <div className="flex items-center gap-2">
        <Checkbox id="remember" />
        <Label htmlFor="remember">Remember me</Label>
      </div>

      {/* Radio */}
      <fieldset className="flex max-w-md flex-col gap-4">
        <legend className="mb-4">Choose your delivery</legend>
        <div className="flex items-center gap-2">
          <Radio id="standard" name="delivery" value="standard" defaultChecked />
          <Label htmlFor="standard">Standard (5-7 days)</Label>
        </div>
        <div className="flex items-center gap-2">
          <Radio id="express" name="delivery" value="express" />
          <Label htmlFor="express">Express (1-2 days)</Label>
        </div>
      </fieldset>

      {/* File Input */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="file" value="Upload file" />
        </div>
        <FileInput id="file" />
      </div>

      {/* Toggle Switch */}
      <ToggleSwitch
        checked={true}
        label="Enable notifications"
        onChange={() => {}}
      />

      {/* Range Slider */}
      <div>
        <div className="mb-2 block">
          <Label htmlFor="default-range" value="Default range" />
        </div>
        <RangeSlider id="default-range" />
      </div>

      <Button type="submit">Submit</Button>
    </form>
  )
}

Card

Code
TypeScript
import { Button, Card } from 'flowbite-react'

function CardExamples() {
  return (
    <div className="flex flex-wrap gap-4">
      {/* Basic card */}
      <Card className="max-w-sm">
        <h5 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
          Noteworthy technology acquisitions 2021
        </h5>
        <p className="font-normal text-gray-700 dark:text-gray-400">
          Here are the biggest enterprise technology acquisitions of 2021.
        </p>
      </Card>

      {/* Card with button */}
      <Card className="max-w-sm">
        <h5 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
          Noteworthy technology acquisitions 2021
        </h5>
        <p className="font-normal text-gray-700 dark:text-gray-400">
          Here are the biggest enterprise technology acquisitions.
        </p>
        <Button>
          Read more
          <svg
            className="-mr-1 ml-2 h-4 w-4"
            fill="currentColor"
            viewBox="0 0 20 20"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path
              fillRule="evenodd"
              d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
              clipRule="evenodd"
            />
          </svg>
        </Button>
      </Card>

      {/* Card with image */}
      <Card
        className="max-w-sm"
        imgAlt="Meaningful alt text"
        imgSrc="/card-image.jpg"
      >
        <h5 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
          Noteworthy technology acquisitions 2021
        </h5>
        <p className="font-normal text-gray-700 dark:text-gray-400">
          Here are the biggest enterprise technology acquisitions.
        </p>
      </Card>

      {/* Horizontal card */}
      <Card
        className="max-w-sm"
        imgAlt="Meaningful alt text"
        imgSrc="/card-image.jpg"
        horizontal
      >
        <h5 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
          Horizontal card
        </h5>
        <p className="font-normal text-gray-700 dark:text-gray-400">
          This is a horizontal card layout.
        </p>
      </Card>
    </div>
  )
}

Toast

Code
TypeScript
import { Toast, ToastToggle } from 'flowbite-react'
import { HiCheck, HiExclamation, HiX, HiFire } from 'react-icons/hi'

function ToastExamples() {
  return (
    <div className="flex flex-col gap-4">
      {/* Success toast */}
      <Toast>
        <div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-green-100 text-green-500 dark:bg-green-800 dark:text-green-200">
          <HiCheck className="h-5 w-5" />
        </div>
        <div className="ml-3 text-sm font-normal">Item moved successfully.</div>
        <ToastToggle />
      </Toast>

      {/* Error toast */}
      <Toast>
        <div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-red-100 text-red-500 dark:bg-red-800 dark:text-red-200">
          <HiX className="h-5 w-5" />
        </div>
        <div className="ml-3 text-sm font-normal">Item has been deleted.</div>
        <ToastToggle />
      </Toast>

      {/* Warning toast */}
      <Toast>
        <div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-orange-100 text-orange-500 dark:bg-orange-700 dark:text-orange-200">
          <HiExclamation className="h-5 w-5" />
        </div>
        <div className="ml-3 text-sm font-normal">Improve password difficulty.</div>
        <ToastToggle />
      </Toast>

      {/* Custom icon */}
      <Toast>
        <div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-cyan-100 text-cyan-500 dark:bg-cyan-800 dark:text-cyan-200">
          <HiFire className="h-5 w-5" />
        </div>
        <div className="ml-3 text-sm font-normal">
          Set yourself free.
        </div>
        <ToastToggle />
      </Toast>
    </div>
  )
}

Flowbite blocks

Flowbite offers 450+ ready-made blocks (page sections) that you can copy and use. Here are the categories:

Available categories:

  • Marketing: Hero, Feature, CTA, Content, Testimonial, Blog, Newsletter, Contact
  • Application: Sidebar, Navbar, Footer, CRUD tables, User cards
  • Publisher: Article, Blog post, Comment sections
  • E-commerce: Product cards, Cart, Checkout, Pricing

Hero Block Example (Copy-paste HTML)

Code
HTML
<section class="bg-white dark:bg-gray-900">
    <div class="grid max-w-screen-xl px-4 py-8 mx-auto lg:gap-8 xl:gap-0 lg:py-16 lg:grid-cols-12">
        <div class="mr-auto place-self-center lg:col-span-7">
            <h1 class="max-w-2xl mb-4 text-4xl font-extrabold tracking-tight leading-none md:text-5xl xl:text-6xl dark:text-white">
                Payments tool for software companies
            </h1>
            <p class="max-w-2xl mb-6 font-light text-gray-500 lg:mb-8 md:text-lg lg:text-xl dark:text-gray-400">
                From checkout to global sales tax compliance, companies around the world use Flowbite to simplify their payment stack.
            </p>
            <a href="#" class="inline-flex items-center justify-center px-5 py-3 mr-3 text-base font-medium text-center text-white rounded-lg bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 dark:focus:ring-primary-900">
                Get started
            </a>
            <a href="#" class="inline-flex items-center justify-center px-5 py-3 text-base font-medium text-center text-gray-900 border border-gray-300 rounded-lg hover:bg-gray-100 focus:ring-4 focus:ring-gray-100 dark:text-white dark:border-gray-700 dark:hover:bg-gray-700 dark:focus:ring-gray-800">
                Speak to Sales
            </a>
        </div>
        <div class="hidden lg:mt-0 lg:col-span-5 lg:flex">
            <img src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/hero/phone-mockup.png" alt="mockup">
        </div>
    </div>
</section>

Pricing Block Example

Code
HTML
<section class="bg-white dark:bg-gray-900">
  <div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
    <div class="mx-auto max-w-screen-md text-center mb-8 lg:mb-12">
      <h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900 dark:text-white">
        Designed for business teams like yours
      </h2>
      <p class="mb-5 font-light text-gray-500 sm:text-xl dark:text-gray-400">
        Here at Flowbite we focus on markets where technology, innovation, and capital can unlock long-term value.
      </p>
    </div>
    <div class="space-y-8 lg:grid lg:grid-cols-3 sm:gap-6 xl:gap-10 lg:space-y-0">
      <!-- Pricing Card -->
      <div class="flex flex-col p-6 mx-auto max-w-lg text-center text-gray-900 bg-white rounded-lg border border-gray-100 shadow dark:border-gray-600 xl:p-8 dark:bg-gray-800 dark:text-white">
        <h3 class="mb-4 text-2xl font-semibold">Starter</h3>
        <p class="font-light text-gray-500 sm:text-lg dark:text-gray-400">
          Best option for personal use & for your next project.
        </p>
        <div class="flex justify-center items-baseline my-8">
          <span class="mr-2 text-5xl font-extrabold">$29</span>
          <span class="text-gray-500 dark:text-gray-400">/month</span>
        </div>
        <!-- List -->
        <ul role="list" class="mb-8 space-y-4 text-left">
          <li class="flex items-center space-x-3">
            <svg class="flex-shrink-0 w-5 h-5 text-green-500 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20">
              <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
            </svg>
            <span>Individual configuration</span>
          </li>
          <li class="flex items-center space-x-3">
            <svg class="flex-shrink-0 w-5 h-5 text-green-500 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20">
              <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
            </svg>
            <span>No setup, or hidden fees</span>
          </li>
        </ul>
        <a href="#" class="text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:ring-primary-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:text-white dark:focus:ring-primary-900">
          Get started
        </a>
      </div>
      <!-- More cards... -->
    </div>
  </div>
</section>

Dark mode

Flowbite fully supports dark mode through the dark: class:

JStailwind.config.js
JavaScript
// tailwind.config.js
module.exports = {
  darkMode: 'class',
  // ...
}
Code
TypeScript
// Dark mode toggle
import { useState, useEffect } from 'react'
import { DarkThemeToggle } from 'flowbite-react'

function DarkModeToggle() {
  return (
    <DarkThemeToggle />
  )
}

// Or custom implementation
function CustomDarkModeToggle() {
  const [isDark, setIsDark] = useState(false)

  useEffect(() => {
    if (isDark) {
      document.documentElement.classList.add('dark')
    } else {
      document.documentElement.classList.remove('dark')
    }
  }, [isDark])

  return (
    <button onClick={() => setIsDark(!isDark)}>
      {isDark ? '🌙' : '☀️'}
    </button>
  )
}

Flowbite icons

Flowbite also offers a set of over 750 free SVG icons: 411 in the outline style and 340 in the solid one. The raw SVG files sit in the flowbite-icons package, while ready made React components live in a separate flowbite-react-icons package split across two entry points.

Code
Bash
npm install flowbite-react-icons
Code
TypeScript
import { Search, User, Bell } from 'flowbite-react-icons/outline'
import { Search as SearchSolid, User as UserSolid, Bell as BellSolid } from 'flowbite-react-icons/solid'

function IconsExample() {
  return (
    <div className="flex gap-4">
      {/* Outline icons */}
      <Search className="w-6 h-6" />
      <User className="w-6 h-6" />
      <Bell className="w-6 h-6" />

      {/* Solid icons */}
      <SearchSolid className="w-6 h-6" />
      <UserSolid className="w-6 h-6" />
      <BellSolid className="w-6 h-6" />
    </div>
  )
}

The free and paid tiers

The split is clear here and worth understanding before starting a project, because it determines how much you actually get for nothing.

The library core is MIT licensed and covers the components: buttons, forms, tables, modal dialogs, dropdowns, and the rest of the elements an interface is built from. That suffices to build a working application and carries no fee and no attribution requirement.

What is paid sits a level up: ready made blocks, meaning composed page sections, complete dashboard and shop templates, and Figma design files. That is the same difference as between a brick and a finished wall: free components hand you elements, paid blocks hand you a page assembled from them.

Specific amounts are deliberately absent, because the pricing page renders only in a browser and cannot be quoted reliably, while the roundups circulating online disagree with each other. The model is a one off purchase with lifetime access, so there is no subscription, but check the current figure directly before buying.

The question worth asking before deciding: are you short of elements or short of an idea for arranging them. In the first case the free tier suffices. In the second you are paying for composition and for time you will not spend adjusting spacing, and that can be worth its price on a site that has to ship in a week.

FAQ - frequently asked questions

Does Flowbite require JavaScript?

For static components (buttons, cards, typography) - no. For interactive ones (dropdown, modal, datepicker) - yes.

Does Flowbite work with Next.js?

Yes! flowbite-react is fully compatible with Next.js App Router.

How do I add custom styles to components?

Use the className or theme prop:

Code
TypeScript
<Button className="my-custom-class">
  Custom styled
</Button>

// Or with theme
<Button theme={{ base: "my-custom-base-class" }}>
  Theme styled
</Button>

Can I use Flowbite with Vite?

Yes, Flowbite works with all bundlers - Vite, Webpack, esbuild, etc.

What's the difference between Flowbite and DaisyUI?

Flowbite offers JavaScript components for interactivity (modal, dropdown), DaisyUI is CSS only. Flowbite supports multiple frameworks, DaisyUI works everywhere Tailwind does.

Are the components accessible to screen readers?

Partly, and it is worth checking yourself for the elements you care about. The markup carries role attributes, but the extent of keyboard handling and focus management varies between components and between the framework variants.

Accessibility, what to ask before choosing

This section matters more than its length in most component library write ups suggests, because it concerns something invisible at first impression.

Libraries of this kind fall into two groups. Some build on a behaviour layer written with accessibility in mind and tested for it, and then the focus trap in a modal, arrow key handling in a menu, and screen reader announcements arrive with the component. Others implement behaviour themselves, guided mainly by making it look right and respond to clicks.

Flowbite belongs to the second group, and that is a deliberate trade rather than negligence. You gain independence from extra dependencies and the ability to use the same markup in plain HTML; you lose the guarantee that every component behaves correctly without a mouse.

A practical test takes a few minutes and is worth running on the components central to your interface. Open a modal from the keyboard, check that focus moved inside, that tab does not escape it, that escape closes it, and that focus returned to the triggering button afterwards. Do the same with a dropdown and arrow keys. If any condition fails, you know how much work to budget.

For a project where accessibility is a formal requirement, the alternative is a set built on a behaviour layer, Headless UI or Radix UI for instance, with the appearance assembled yourself. That costs more work up front and repays at audit time.

The source and component list live in the Flowbite repository, and documentation on the project site.