Skip to content

shadcn.io is an independent project built on shadcn/ui

Heading Selector Dropdown Menu for React

A heading level picker from H1 to H6, each row drawn at its own size and the button showing the current level.

The outline button shows the current level, starting at H1. Heading 1 through Heading 6 are radio items, each drawn at its own size, and only one stays checked.

Use it in a document editor when the level should be obvious before the click. The rows are not real headings. For a form field, use a Select. In React, Base UI stores the level and does not change the document.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Dropdown Menu anatomy: trigger, label, item, shortcut, separator, sub trigger, content

Usage

<DropdownMenu>
  <DropdownMenuTrigger render={<Button variant="outline" />}>
    <HeadingIcon aria-hidden="true" data-icon="inline-start" />
    {heading.toUpperCase()}
  </DropdownMenuTrigger>
  <DropdownMenuContent className="w-48">
    <DropdownMenuRadioGroup onValueChange={setHeading} value={heading}>
      <DropdownMenuRadioItem value="h1">
        <span className="font-bold text-2xl">Heading 1</span>
      </DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="h2">
        <span className="font-bold text-xl">Heading 2</span>
      </DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="h3">
        <span className="font-bold text-lg">Heading 3</span>
      </DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="h4">
        <span className="font-bold text-base">Heading 4</span>
      </DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="h5">
        <span className="font-bold text-sm">Heading 5</span>
      </DropdownMenuRadioItem>
      <DropdownMenuRadioItem value="h6">
        <span className="font-bold text-xs">Heading 6</span>
      </DropdownMenuRadioItem>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

FAQ

How does the current heading show on the button?

The value starts at h1, and the button prints it in uppercase, H1, after a heading icon. Picking another row updates the value and the button. DropdownMenuRadioGroup takes value, and onValueChange receives the new value.

How are the rows sized?

Each row wraps its label in a bold span: Heading 1 is text-2xl, then text-xl, text-lg, text-base and text-sm, down to text-xs for Heading 6.

How wide is the menu?

w-48, and the six radio rows are the whole menu.

Can two heading levels be selected?

No. The radio group keeps one value. Choosing Heading 3 stores h3, moves the check to that row and changes the button to H3.

Can I pick a heading from the keyboard?

Yes. Arrow Up and Arrow Down move between rows, Enter picks one, typing H jumps through the Heading rows, and Escape closes the menu and returns focus to the button.

Are the rows real heading elements?

No. Each row's label is a styled span, which keeps the menu's structure valid for screen readers. The value is just the string h1 to h6; apply the real heading in your editor.

API Reference

Dropdown Menu

Sets onValueChange={setHeading}, value={heading}, value="h1", value="h2", value="h3" and value="h4". The rest is on the Dropdown Menu page.

Button

Sets variant="outline". The rest is on the Button page.