# How to Build a Bootstrap Select with Search Using Tailwind CSS

> Build a Bootstrap select with search using Tailwind CSS. Learn to style dropdowns with utility classes and implement filtering logic with JavaScript or the @apply directive.

- Repository: [Tailwind Labs/tailwindcss](https://github.com/tailwindlabs/tailwindcss)
- Tags: how-to-guide
- Published: 2026-02-16

---

**You can implement a Bootstrap-style select with search functionality in Tailwind CSS by composing utility classes for the dropdown styling and JavaScript for the filtering logic, or by extracting reusable styles using the `@apply` directive and the plugin API.**

The Tailwind CSS compiler, located in the `tailwindlabs/tailwindcss` repository, generates optimized CSS by parsing your markup and expanding utility classes at build time. To create a **bootstrap select with search** component, you leverage this utility-first architecture—combining layout, spacing, and color utilities with the framework's design system to build accessible, searchable dropdowns without writing custom CSS from scratch.

## Understanding Tailwind's Compiler Architecture

Before building the component, it helps to understand how Tailwind processes your styles. The compiler transforms utility classes into optimized CSS through a series of discrete steps orchestrated by the design system.

### Entry Point and Compile Flow

The public API lives in **[`packages/tailwindcss/src/index.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/index.ts)**. It exposes `compile(css, opts)` which orchestrates the build pipeline:

1. **Parse** the input CSS into an AST using `CSS.parse`.
2. **Collect** Tailwind directives (`@tailwind utilities`, `@theme`, custom `@utility` rules) via `parseCss`.
3. **Build** the **Design System** using `buildDesignSystem`, which holds the theme, generated utilities, and variant registry.
4. **Substitute** at-rules (`@apply`, `@import`, `@variant`) and functions (`theme()`, `color-mix()`).
5. **Optimize** the AST by removing unused utilities and merging selectors.
6. **Serialize** the AST back into a CSS string.

> Source: [index.ts – compile flow](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/index.ts)

### Design System and Theme Resolution

The `buildDesignSystem` function in **[`packages/tailwindcss/src/design-system.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/design-system.ts)** creates three core objects that power every utility class:

| Component | Responsibility |
|-----------|----------------|
| **Theme** | Stores CSS custom properties and resolves `theme()` calls, supporting prefixes and reference mode. |
| **Utilities** | Generates utility rules from core configuration (e.g., `bg-red-500`, `rounded`). |
| **Variants** | Handles responsive, state, and custom variants (e.g., `hover:`, `focus-visible:`). |

The theme resolution logic resides in **[`packages/tailwindcss/src/theme.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/theme.ts)**, which manages CSS custom properties and the `theme()` function resolution used throughout the compiler.

> Source: [design-system.ts](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/design-system.ts)

## Building a Bootstrap Select with Search Component

With the compiler architecture in mind, you can construct the searchable dropdown using three different approaches: pure utilities, `@apply` composition, or a custom plugin.

### Pure Utility Class Implementation

The most straightforward method uses only Tailwind's utility classes in your HTML. This approach ensures maximum tree-shaking since only used utilities are included in the final bundle.

```html
<div class="relative inline-block w-64">
  <!-- Search input -->
  <input
    type="text"
    placeholder="Search…"
    class="block w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-sm leading-5 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
    id="search-input"
  />

  <!-- Dropdown list -->
  <ul
    class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm hidden"
    role="listbox"
    id="options-list"
  >
    <li
      class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-indigo-100"
      role="option"
    >Apple</li>
    <li
      class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-indigo-100"
      role="option"
    >Banana</li>
    <li
      class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-indigo-100"
      role="option"
    >Cherry</li>
  </ul>
</div>

```

All classes are resolved by the `createUtilities(theme)` function in **[`packages/tailwindcss/src/utilities.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/utilities.ts)**, which generates the CSS rules from your theme configuration.

### Using @apply for Reusable Styles

For projects requiring repeated use of this pattern, the `@apply` directive—processed in **[`packages/tailwindcss/src/apply.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/apply.ts)**—lets you extract utility combinations into component classes.

Create a [`components.css`](https://github.com/tailwindlabs/tailwindcss/blob/main/components.css) file:

```css
@layer components {
  .searchable-select-item {
    @apply relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-indigo-100;
  }
}

```

Your HTML becomes cleaner:

```html
<li class="searchable-select-item" role="option">Apple</li>

```

During compilation, the `@apply` rule is expanded to the underlying utility AST nodes, maintaining the same optimization benefits as inline utilities.

### Creating a Custom Plugin

For the most maintainable solution, use the Plugin API defined in **[`packages/tailwindcss/src/compat/plugin-api.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/compat/plugin-api.ts)**. This allows you to register a dedicated `.searchable-select` component that generates all necessary styles.

Create [`tailwind.searchable-select.js`](https://github.com/tailwindlabs/tailwindcss/blob/main/tailwind.searchable-select.js):

```js
module.exports = function ({ addComponents, theme }) {
  const components = {
    '.searchable-select': {
      '@apply relative inline-block w-64': {},
      'input': {
        '@apply block w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 text-sm leading-5 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500': {},
      },
      'ul': {
        '@apply absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm hidden': {},
      },
      'li': {
        '@apply relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-indigo-100': {},
      },
    },
  }
  addComponents(components)
}

```

Register it in [`tailwind.config.js`](https://github.com/tailwindlabs/tailwindcss/blob/main/tailwind.config.js):

```js
module.exports = {
  content: ['./**/*.html'],
  plugins: [require('./tailwind.searchable-select.js')],
}

```

Now implement the component with a single class:

```html
<div class="searchable-select">
  <input type="text" placeholder="Search…" />
  <ul role="listbox">
    <li role="option">Apple</li>
    <li role="option">Banana</li>
    <li role="option">Cherry</li>
  </ul>
</div>

```

The plugin leverages the same **design-system → utilities** pipeline described in `buildDesignSystem`, ensuring the generated CSS remains tree-shaken and theme-aware.

## Utility Generation and Variant Handling

### How Utilities Are Generated

The `createUtilities(theme)` function in **[`packages/tailwindcss/src/utilities.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/utilities.ts)** iterates over the resolved theme (spacing, colors, fonts) and produces a map of class names to AST nodes. Each utility is cached for fast rebuilds, which is why the searchable select examples above compile quickly even with many utility combinations.

### Adding Interactive States

Interactive states like `hover:bg-indigo-100` or `focus:ring-indigo-500` are handled by the variant system in **[`packages/tailwindcss/src/variants.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/variants.ts)**. Standard variants are defined here, and custom variants can be added via the plugin API using `addVariant`. The compiler records variant order to ensure generated CSS respects the same precedence as your source markup, which is critical for maintaining the correct cascade in your searchable dropdown's hover and focus states.

## Summary

- **Tailwind CSS** generates styles through a compiler pipeline ([`packages/tailwindcss/src/index.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/index.ts)) that parses utilities, builds a design system, and optimizes the output.
- You can implement a **bootstrap select with search** using pure utility classes for maximum tree-shaking, or extract patterns using `@apply` ([`packages/tailwindcss/src/apply.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/apply.ts)).
- For reusable components, the Plugin API ([`packages/tailwindcss/src/compat/plugin-api.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/compat/plugin-api.ts)) lets you register custom component classes that integrate with the design system.
- Utility generation ([`packages/tailwindcss/src/utilities.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/utilities.ts)) and variant handling ([`packages/tailwindcss/src/variants.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/variants.ts)) ensure your interactive dropdown states compile efficiently.

## Frequently Asked Questions

### How does Tailwind CSS differ from Bootstrap when building searchable select components?

Unlike Bootstrap's pre-built JavaScript components, Tailwind CSS is a utility-first framework that generates CSS at build time based on classes you use in your markup. According to the source code in [`packages/tailwindcss/src/index.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/index.ts), the `compile()` function parses your HTML, expands utilities via `createUtilities()` in [`packages/tailwindcss/src/utilities.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/utilities.ts), and outputs optimized CSS. This means you compose your searchable select from atomic utilities rather than overriding pre-defined component styles.

### Can I use the @apply directive to create a reusable searchable select pattern?

Yes. The `@apply` directive, implemented in [`packages/tailwindcss/src/apply.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/apply.ts), allows you to inline utility classes into custom CSS rules. You can create a `.searchable-select-item` class that uses `@apply` to bundle `relative`, `cursor-default`, `select-none`, and hover states. During compilation, Tailwind expands these references into the actual utility AST nodes, maintaining the same optimization benefits as inline utilities while keeping your HTML markup clean.

### How do I add custom interactive states to my searchable select dropdown?

Interactive states like `hover:bg-indigo-100` or `focus:ring-indigo-500` are handled by the variant system defined in [`packages/tailwindcss/src/variants.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/variants.ts). The compiler records variant order to ensure generated CSS respects the same precedence as your source markup. You can also register custom variants via the Plugin API in [`packages/tailwindcss/src/compat/plugin-api.ts`](https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/src/compat/plugin-api.ts) using the `addVariant` function, allowing you to create bespoke states for your searchable select component while maintaining proper cascade order.