• CMSnpm version

    • Overview
    • ContentBuilder
    • InviteUserForm
    • LoginForm
    • RenewPasswordForm
    • WysiwygInput
  • UInpm version

    • Overview
    • Accordion
    • AlertBubble
    • AnnouncementBar
    • Avatar
    • AvatarFileInput
    • Badge
    • Button
    • ButtonGroup
    • ButtonList
    • Calendar
    • Checkbox
    • CheckboxButton
    • CheckboxInput
    • CheckboxList
    • Chip
    • ColorRadio
    • ColorRadioGroup
    • Combobox
    • DatePicker
    • DatePickerInput
    • DateRangePicker
    • DateRangePickerInput
    • DatetimePicker
    • DatetimePickerInput
    • Dialog
    • Dropdown
    • Dropzone
    • ErrorMessage
    • FileInput
    • FlashMessages
    • FormComponent
    • Icon
    • IconButton
    • ImageGallery
    • InfoBox
    • Input
    • Label
    • Layout
    • Lightbox
    • ListItem
    • Loader
    • Lozenge
    • Menu
    • Message
    • Modal
    • ✅ ModalDialog
    • ✅ ModalHeader
    • MultiCombobox
    • MultiSelect
    • Pagination
    • Paper
    • Popover
    • Radio
    • RadioGroup
    • RasterImage
    • Select
    • Switch
    • ✅ Tabs
    • TextInput
    • TextLink
    • Textarea
    • TimePicker
    • TimePickerInput
    • Toggle
    • Tooltip
    • Typography
  • Formnpm version

    • Overview
    • AvatarFileInput
    • CheckboxButton
    • CheckboxInput
    • CheckboxList
    • ColorRadioGroup
    • Combobox
    • DatePickerInput
    • DateRangePickerInput
    • DatetimePickerInput
    • Dropzone
    • FileInput
    • Form
    • FormRenderer
    • GpsInput
    • MoneyInput
    • MultiCombobox
    • MultiSelect
    • NumberInput
    • PasswordInput
    • RadioGroup
    • Select
    • TextInput
    • Textarea
    • TimePickerInput
    • Toggle
  • DataGridnpm version

    • Overview
    • DataGrid
    • DataGridCustomExample
    • ExportButton
    • FilterList
    • Filters
    • FiltersButton
    • FulltextInput
    • HiddenColumns
    • HiddenColumnsButton
    • Pagination
    • RowCounts
    • RowsPerPageSelect
    • SelectedRowsToolbar
    • TableV2
    • ToolbarControl
    • ToolbarCustoms
    • ToolbarTabs
  • Wysiwygnpm version

    • Overview
  • Resizernpm version

    • Overview
  • Routernpm version

    • Overview
  • Corenpm version

    • Overview
  • Core-Reactnpm version

    • Overview
  • DnDnpm version

    • Overview
  • Stylesnpm version

    • Overview
  • Localizenpm version

    • Overview
  • Analyticsnpm version

    • Overview
  • Datepickernpm version

    • Overview
  • Icons-generatornpm version

    • Overview
  • Smart-addressnpm version

    • Overview
  • E2Enpm version

    • Overview
  • E2E-Playwrightnpm version

    • Overview
View source on GitLab

Dropdown

Presentational parts for a dropdown menu: a styled container (Dropdown.Items) and anchor-based menu items (Dropdown.Item). It provides styling and item semantics only — pair it with a headless behaviour/positioning layer such as @base-ui/react's Menu.

When to use

Use Dropdown when you need the visual menu panel and items but are driving open/close and positioning with Base UI (or similar). It does not position itself — there is no @floating-ui logic here.

  • For a full floating panel with built-in open/dismiss behaviour, use Popover.
  • For app navigation (sidebar-style, active-route aware), use Menu.

There is no @uxf/form twin.

Usage

Grounded in the story — Base UI's Menu handles state and positioning; Dropdown supplies the styled surface. Menu.Root renders no host element, so the wrapper <div className="relative"> is written out explicitly, and a single Menu.Item with a render prop is both the menu item and the styled item. (Before the migration to Base UI, the equivalent state came from Headless UI's render prop as active; today it is state.highlighted.)

uxf-dropdown is position: absolute by default, which is what the standalone recipe (a relative wrapper and no headless positioner) needs. Because the panel below is placed by Menu.Positioner, it opts into position: relative with uxf-dropdown--positioned — without it the positioner has an out-of-flow child and collapses to zero size.

The panel classes go straight on Menu.Popup's className, not through Dropdown.Items: Dropdown.Items only forwards className, role, children and ref, so passing it to Menu.Popup via render would silently drop every other prop Base UI's popup needs to be keyboard-navigable (its own id, event handlers, tabIndex, …). Same pattern as button-list.tsx's own menu.

import { Menu } from "@base-ui/react/menu";
import { CLASSES } from "@uxf/core/constants/classes";
import { Button } from "@uxf/ui/button";
import { Dropdown } from "@uxf/ui/dropdown";

const items = [
    { id: 1, title: "Test 1" },
    { id: 2, title: "Test 2" },
];

<div className="relative">
    <Menu.Root>
        {/* `Button` renders an <a>, so Base UI must not assume native button semantics. */}
        <Menu.Trigger nativeButton={false} render={<Button color="positive">Click me</Button>} />
        <Menu.Portal>
            <Menu.Positioner align="start" side="bottom" sideOffset={0}>
                <Menu.Popup className="uxf-dropdown uxf-dropdown--positioned">
                    {items.map((item) => (
                        <Menu.Item
                            key={item.id}
                            render={(itemProps, state) => (
                                <Dropdown.Item {...itemProps} className={state.highlighted ? CLASSES.IS_ACTIVE : ""}>
                                    {item.title}
                                </Dropdown.Item>
                            )}
                        />
                    ))}
                </Menu.Popup>
            </Menu.Positioner>
        </Menu.Portal>
    </Menu.Root>
</div>;

API

Import: import { Dropdown } from "@uxf/ui/dropdown".

Dropdown.Items

The menu panel — a <div className="uxf-dropdown"> that forwards its ref. Accepts standard HTMLAttributes<HTMLDivElement> (className, role, children, …); the passed role is forwarded to the div. (The exported DropdownItemsProps type is the ref element type HTMLDivElement, not the props type.)

Dropdown.Item

A single item, rendered as an <a> (or a Next.js link via as) with role="menuitem" and class uxf-dropdown__item.

DropdownItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> (minus type) plus UseAnchorProps:

PropTypeDefaultDescription
as"a" | NextLink"a"Element to render. Pass a Next.js Link for client-side navigation.
isDisabledbooleanfalseNon-interactive state (adds the disabled class, drops it from tab order).
isLoadingbooleanfalseBusy state.
analyticsCallback() => void—Called when the item is activated.
type"submit"—Submit the closest <form> on activation; the only accepted type.

Standard anchor attributes (href, onClick, className, children, …) are also accepted.

Variants & states

Item state is driven by classes on uxf-dropdown__item (typically supplied by the headless layer's render props):

ClassMeaning
is-activeHighlighted / keyboard-active item. Use CLASSES.IS_ACTIVE from @uxf/core/constants/classes.
is-selectedCurrently selected value.
is-disabledDisabled item.

The panel itself takes one modifier:

ClassMeaning
uxf-dropdown--positionedSomething else owns the placement (a Base UI Positioner, or any wrapper that already sizes the box) — switches the panel from position: absolute to relative.

The stylesheet also defines a uxf-dropdown__items class that is deprecated — use Dropdown.Items (which renders uxf-dropdown). It is position: absolute, matching the base uxf-dropdown rule.

Requirements

Import the component stylesheet once in your global CSS:

@import url("@uxf/ui/css/dropdown.css");

Also requires the global @uxf/ui token layer, set up once per app — see @uxf/ui setup.

Default
Open in new tab