Propel

Select

Lets a user choose one option from a list in a popup.

Server type
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function BasicDemo() {
  return (
    <Select items={SERVER_TYPES} defaultValue="general">
      <SelectField>
        <SelectLabel size="lg">Server type</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value }) => (
            <SelectItem key={value} value={value} label={label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Installation

import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";

Usage

import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function BasicDemo() {
  return (
    <Select items={SERVER_TYPES} defaultValue="general">
      <SelectField>
        <SelectLabel size="lg">Server type</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value }) => (
            <SelectItem key={value} value={value} label={label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Examples

Placeholder

Without a defaultValue, the trigger shows its placeholder until an option is picked.

Server type
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function PlaceholderDemo() {
  return (
    <Select items={SERVER_TYPES}>
      <SelectField>
        <SelectLabel size="lg">Server type</SelectLabel>
        <SelectTrigger size="lg" placeholder="Choose a server type" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value }) => (
            <SelectItem key={value} value={value} label={label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Multiple

Server types
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function MultipleDemo() {
  return (
    <Select multiple items={SERVER_TYPES} defaultValue={["general", "compute"]}>
      <SelectField>
        <SelectLabel size="lg">Server types</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value }) => (
            <SelectItem key={value} value={value} label={label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

SelectContent pins sticky content above and below the scrolling list: header and footer. For a multiple select, put a SelectSelectAll row (and a SelectSeparator) in a SelectStickyList in the header, wired to the controlled value: it shows a dash while only some options are picked. A SelectFooter in the footer holds a hint or a count.

Server types
Show code
import {
  Select,
  SelectContent,
  SelectFooter,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectSelectAll,
  SelectSeparator,
  SelectStickyList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";
import { useState } from "react";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function SelectAllDemo() {
  const [value, setValue] = useState<string[]>(["general"]);
  const allSelected = value.length === SERVER_TYPES.length;
  return (
    <Select multiple items={SERVER_TYPES} value={value} onValueChange={setValue}>
      <SelectField>
        <SelectLabel size="lg">Server types</SelectLabel>
        <SelectTrigger size="lg" placeholder="Choose server types" />
      </SelectField>
      <SelectContent
        header={
          <SelectStickyList>
            <SelectSelectAll
              checked={allSelected}
              indeterminate={value.length > 0 && !allSelected}
              onClick={() => setValue(allSelected ? [] : SERVER_TYPES.map((type) => type.value))}
            />
            <SelectSeparator />
          </SelectStickyList>
        }
        footer={
          <SelectFooter>
            {value.length} of {SERVER_TYPES.length} selected
          </SelectFooter>
        }
      >
        <SelectList>
          {SERVER_TYPES.map((type) => (
            <SelectItem key={type.value} value={type.value} label={type.label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Grouped

Group related options under a SelectGroup with a SelectGroupLabel, and divide the groups with a SelectSeparator. The label’s meta pins content at its end, such as a count; it is left out of the group’s accessible name.

Region
Show code
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectGroupLabel,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectSeparator,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";
import { Fragment } from "react";

const REGION_GROUPS = [
  {
    label: "Americas",
    items: [
      { label: "US Central 1", value: "us-central-1" },
      { label: "US East 1", value: "us-east-1" },
    ],
  },
  {
    label: "Europe",
    items: [
      { label: "EU Central 1", value: "eu-central-1" },
      { label: "EU West 1", value: "eu-west-1" },
    ],
  },
];

export default function GroupedDemo() {
  return (
    <Select items={REGION_GROUPS.flatMap((group) => group.items)} defaultValue="us-central-1">
      <SelectField>
        <SelectLabel size="lg">Region</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {REGION_GROUPS.map((group, index) => (
            <Fragment key={group.label}>
              {index > 0 ? <SelectSeparator /> : null}
              <SelectGroup>
                <SelectGroupLabel meta={group.items.length}>{group.label}</SelectGroupLabel>
                {group.items.map(({ label, value }) => (
                  <SelectItem key={value} value={value} label={label} />
                ))}
              </SelectGroup>
            </Fragment>
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Option details

secondaryText adds muted text after an option’s label, and description a muted second line (the row grows to fit it). trailing pins content at the row’s end, after the check. The trigger shows the label alone.

Plan
Show code
import { Badge } from "@makeplane/propel/components/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const PLANS = [
  { label: "Starter", value: "starter", secondaryText: "Free", description: "1 vCPU · 1 GB RAM" },
  { label: "Pro", value: "pro", secondaryText: "$20/mo", description: "2 vCPU · 4 GB RAM" },
  {
    label: "Enterprise",
    value: "enterprise",
    secondaryText: "Custom",
    description: "Dedicated hosts, SSO and audit logs",
  },
];

export default function ItemDetailsDemo() {
  return (
    <Select items={PLANS} defaultValue="pro">
      <SelectField>
        <SelectLabel size="lg">Plan</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {PLANS.map(({ label, value, secondaryText, description }) => (
            <SelectItem
              key={value}
              value={value}
              label={label}
              secondaryText={secondaryText}
              description={description}
              trailing={
                value === "pro" ? <Badge size="xs" variant="brand" label="Popular" /> : undefined
              }
            />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

SelectContent matches the trigger’s width by default (sizing="anchor"). sizing="auto" sizes the popup to its options instead, between 204px and 400px, for a trigger whose options need more (or less) room than it has.

Trigger width

Field-style triggers use width="auto" by default, preserving the existing 288px minimum while allowing the trigger to grow. Use width="fit" when a secondary or ghost trigger should hug its rendered icon, value, chevron, gaps, and padding. This does not change SelectContent sizing; an anchor-sized popup can still grow wider than a compact trigger when its options need more room. The pill variant is already intrinsically sized and does not accept width.

auto
fit
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
  type SelectTriggerWidth,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const PLANS = [
  { label: "Starter", value: "starter" },
  { label: "A considerably longer enterprise plan", value: "enterprise" },
];

const WIDTHS: SelectTriggerWidth[] = ["auto", "fit"];

export default function FitWidthDemo() {
  return (
    <div className="flex flex-wrap items-end gap-4">
      {WIDTHS.map((width) => (
        <Select key={width} items={PLANS} defaultValue="starter">
          <SelectField>
            <SelectLabel size="lg">{width}</SelectLabel>
            <SelectTrigger size="lg" width={width} />
          </SelectField>
          <SelectContent>
            <SelectList>
              {PLANS.map(({ label, value }) => (
                <SelectItem key={value} value={value} label={label} />
              ))}
            </SelectList>
          </SelectContent>
        </Select>
      ))}
    </div>
  );
}

Sizes

For secondary and ghost, size runs md 28 / lg 32 / xl 36 / 2xl 40 px. Pass the same value to SelectLabel and SelectTrigger: the label tracks the trigger’s rung, while the option rows stay one fixed 32px height at every size, like Combobox and Menu rows. The label runs 13px at md and lg, 14px at xl and 2xl — matching what a field wrapper renders at the same control height, so it sits one step calmer than the value at lg and 2xl and matches it at xl. See Sizing for the full ladder.

md
lg
xl
2xl
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
  type SelectTriggerFieldSize,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

const SIZES: SelectTriggerFieldSize[] = ["md", "lg", "xl", "2xl"];

export default function SizesDemo() {
  return (
    <div className="flex flex-wrap items-end gap-3">
      {SIZES.map((size) => (
        <Select key={size} items={SERVER_TYPES} defaultValue="general">
          <SelectField>
            <SelectLabel size={size}>{size}</SelectLabel>
            <SelectTrigger size={size} />
          </SelectField>
          <SelectContent>
            <SelectList>
              {SERVER_TYPES.map(({ label, value }) => (
                <SelectItem key={value} value={value} label={label} />
              ))}
            </SelectList>
          </SelectContent>
        </Select>
      ))}
    </div>
  );
}

Variants

SelectTrigger’s secondary variant (default) is the bordered field surface; ghost drops the border and fill; pill keeps bordered chrome but hugs its value for compact property and filter selectors. Like Propel Pill, the pill trigger has no automatic chevron: an open popup is conveyed by its active chrome. Pair it with SelectContent sizing="auto" so its options are not constrained by the compact anchor width. Its size scale is xs, sm, and md, matching Propel Pill; the type contract rejects those compact sizes on secondary/ghost and rejects lg–2xl on pill.

secondary
ghost
pill
Show code
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
  type SelectTriggerVariant,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

const VARIANTS: SelectTriggerVariant[] = ["secondary", "ghost", "pill"];

export default function VariantsDemo() {
  return (
    <div className="flex flex-wrap items-end gap-3">
      {VARIANTS.map((variant) => (
        <Select key={variant} items={SERVER_TYPES} defaultValue="general">
          <SelectField>
            <SelectLabel size={variant === "pill" ? "md" : "lg"}>{variant}</SelectLabel>
            {variant === "pill" ? (
              <SelectTrigger size="md" variant="pill" />
            ) : (
              <SelectTrigger size="lg" variant={variant} />
            )}
          </SelectField>
          <SelectContent sizing={variant === "pill" ? "auto" : undefined}>
            <SelectList>
              {SERVER_TYPES.map(({ label, value }) => (
                <SelectItem key={value} value={value} label={label} />
              ))}
            </SelectList>
          </SelectContent>
        </Select>
      ))}
    </div>
  );
}

With icon

SelectTrigger’s icon prop shows a leading glyph before the value, via the shared Icon slot.

Server type
Show code
import { Icon } from "@makeplane/propel/components/icon";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";
import { ServerOutline } from "@makeplane/propel/icons";

const SERVER_TYPES = [
  { label: "General purpose", value: "general" },
  { label: "Compute optimized", value: "compute" },
  { label: "Memory optimized", value: "memory" },
];

export default function WithIconDemo() {
  return (
    <Select items={SERVER_TYPES} defaultValue="general">
      <SelectField>
        <SelectLabel size="lg">Server type</SelectLabel>
        <SelectTrigger size="lg" icon={<Icon icon={ServerOutline} tint="placeholder" />} />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value }) => (
            <SelectItem key={value} value={value} label={label} />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

Option icons

SelectItem’s icon prop shows a leading glyph before an option’s label. In a multiple select it follows the checkbox.

Server type
Show code
import { Icon } from "@makeplane/propel/components/icon";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectLabel,
  SelectList,
  SelectTrigger,
} from "@makeplane/propel/components/select";
import { SelectField } from "@makeplane/propel/elements/select";
import { ModuleOutline, MemoryOutline, ServerOutline } from "@makeplane/propel/icons";

const SERVER_TYPES = [
  { label: "General purpose", value: "general", icon: ServerOutline },
  { label: "Compute optimized", value: "compute", icon: ModuleOutline },
  { label: "Memory optimized", value: "memory", icon: MemoryOutline },
];

export default function ItemIconsDemo() {
  return (
    <Select items={SERVER_TYPES} defaultValue="general">
      <SelectField>
        <SelectLabel size="lg">Server type</SelectLabel>
        <SelectTrigger size="lg" />
      </SelectField>
      <SelectContent>
        <SelectList>
          {SERVER_TYPES.map(({ label, value, icon }) => (
            <SelectItem
              key={value}
              value={value}
              label={label}
              icon={<Icon icon={icon} tint="secondary" />}
            />
          ))}
        </SelectList>
      </SelectContent>
    </Select>
  );
}

API Reference

Select

The select Root — Base UI's context/state provider (renders no element of its own). A behavior-only role, so it lives in components (rules 1a, 2); the styled parts live in elements/select and are grafted onto Base UI behavior here. It also shares multiple with its SelectItems, which switch to a leading checkbox marker for a multi-select.

PropTypeDefaultDescription
childrenReactNode—The select's anatomy — a SelectTrigger and the popup of items.

SelectTrigger

The ready-made select trigger: grafts Base UI's Select.Trigger behavior onto the styled trigger and bakes its anatomy — an optional leading icon, the selected value (Base UI's Select.Value grafted onto SelectValue), and an owned chevron indicator for field-style variants. The pill variant follows Propel Pill anatomy and has no baked trailing icon; its open state is conveyed by active chrome. Children are baked, so the prop is omitted.

PropTypeDefaultDescription
size(required)"xs" | "sm" | "md" | "lg" | "xl" | "2xl"—
placeholderReactNode—Shown in the trigger while nothing is selected — Base UI's Select.Value placeholder.
iconReactNode—Element shown before the value, e.g. <Icon icon={Server} tint="placeholder" />.
variant"secondary" | "ghost" | "pill"—
width"auto" | "fit"—auto keeps the 288px minimum; fit hugs the rendered trigger content.

SelectContent

The select list surface: Base UI portal + positioner, with the popup grafted onto the shared OverlayPanel — the same elevated card, radius, open/close animation and anchor width as the Combobox and Menu panels, including the ScrollArea its list scrolls in.

PropTypeDefaultDescription
sizing"auto" | "anchor" | "anchor-fixed"anchorHow the popup takes its width. anchor matches the trigger's width, growing only with its content up to the room beside the trigger. auto is the content's width instead — never narrower than 204px, never wider than 400px or the room beside the trigger — for a narrow trigger (e.g. a ghost select in a toolbar) whose options need more room than it has.
headerReactNode—Sticky content pinned above the scrolling list, e.g. a SelectStickyList holding a SelectSelectAll row and a SelectSeparator.
footerReactNode—Sticky content pinned below the scrolling list, e.g. a SelectFooter.
side"top" | "bottom" | "left" | "right" | "inline-end" | "inline-start"bottomWhich side of the trigger the list opens toward.
sideOffsetnumber | OffsetFunction4Distance in px between the trigger and the list.
align"center" | "start" | "end"startAlignment of the list relative to the trigger along side.
alignOffsetnumber | OffsetFunction0Additional offset in px along the align axis — slides the list along the trigger's edge without changing align.
collisionPaddingPadding16Minimum gap in px between the list and the viewport edge it would otherwise touch.
collisionBoundaryBoundary—The element or rect the list is confined to when avoiding collisions. Base UI's clipping ancestors when unset.
collisionAvoidanceCollisionAvoidance—What to do when the list would overflow the boundary, set per axis: flip to the other side, shift along it, or stay put. Base UI flips the side and shifts the alignment when unset.
stickybooleanfalseKeep the list on screen after the trigger scrolls out of view, instead of following it out.
positionMethod"absolute" | "fixed""absolute"Which CSS position the positioner uses. fixed escapes overflow-clipping ancestors, e.g. a trigger inside a sticky header.
anchorElement | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null—Position against this element instead of the trigger — an element, a ref, a virtual element, or a function returning one. Geometry only; the trigger keeps its role and interactions.
disableAnchorTrackingbooleanfalseStop tracking layout shifts of the anchor — position once, on open.
alignItemWithTriggerbooleanfalseOverlap the popup onto the trigger so the selected item's text lines up with the trigger's value (native <select>-style). Figma's spec opens the list flush below the trigger instead, so this defaults off — enable per-instance for the native-alignment look. While it is on, Base UI scrolls the list element itself rather than the panel's ScrollArea, so the list shows the native scrollbar instead of the panel's.

SelectLabel

The ready-made select label: grafts Base UI's Select.Label behavior — automatic association with the trigger — onto the styled label.

PropTypeDefaultDescription
size(required)"md" | "lg" | "xl" | "2xl"—Label text size. Pass the same step as the SelectTrigger it labels. Required.

SelectList

The container for the select items: Base UI's Select.List grafted onto the styled SelectList, the padded list inside the SelectContent panel (the rows are SelectItems).

No component-specific props — accepts the standard HTML attributes for the element it renders.

SelectItem

The ready-made select option row: grafts Base UI's Select.Item behavior onto the styled SelectItem row — the shared menu-row chrome, so the list matches Combobox and Menu — and lays out an optional leading icon, the label with any inline secondary text, an optional description line, the selection marker, and trailing content. A single-select row trails its label with a check (SelectItemIndicator); inside a multiple select the row leads with a checkbox box (SelectCheckboxItemIndicator), matching a multi-select Combobox. Both markers are keepMounted: the check so its gutter holds while unselected (a selection change never re-truncates a label), the checkbox so the empty box shows. Only the label goes through Base UI's Select.ItemText, so it alone is what the trigger shows for the selected option.

PropTypeDefaultDescription
size"md" | "lg" | "xl" | "2xl""lg"No longer has any effect: option rows are one fixed height, whatever the trigger's size. Still accepted so existing call sites keep compiling — drop it. @deprecated Option rows no longer take a size.
iconReactNode—Leading element shown before the label, e.g. <Icon icon={Server} tint="secondary" />. In a multiple select it follows the checkbox box.
descriptionstring—Muted secondary line under the label. The row grows to fit it.
secondaryTextstring—Muted text shown inline after the label.
trailingReactNode—Content pinned at the row's inline end, after the check, e.g. a count (12) or a <Badge />.
valueunknown—Option value whose string form is used when label is omitted. Option value. Object values cannot derive display text, so they require label.
labelstring—Option label. Defaults to the string form of value. Visible option and typeahead label. Required when value is not a primitive.

SelectGroup

Groups related options under a SelectGroupLabel.

PropTypeDefaultDescription
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectGroupState>—Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render.

SelectGroupLabel

The muted heading naming a SelectGroup, with optional meta pinned at its end. Base UI's GroupLabel behavior is grafted onto the heading's TITLE, not the whole row, so the group's accessible name is the heading text alone — a count or a "Clear" button in meta stays out of it. Place it inside the SelectGroup it names, so Base UI wires it as that group's label.

PropTypeDefaultDescription
metaReactNode—Content pinned at the heading's inline end, e.g. a count or a "Clear" action.

SelectSeparator

A thin divider between groups of options — the same chrome as ComboboxSeparator and MenuSeparator. Purely visual, so it is aria-hidden and carries no separator role: a listbox may only own options and groups, so Base UI's Select.Separator (which renders role="separator") would be invalid ARIA inside the list. The SelectGroup labels already give a screen reader the structure the line shows.

PropTypeDefaultDescription
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>—Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render.

SelectSelectAll

Sticky "select every option" row for a multiple select, the counterpart of ComboboxSelectAll. Not a SelectItem — it is not an option — so compose it in SelectContent's header (inside a SelectStickyList) above the scrolling list, and wire checked / indeterminate / onClick to the select's controlled value.

PropTypeDefaultDescription
checked(required)boolean—Whether every option is currently selected.
onClick(required)() => void—Called when the row is activated.
labelstringSelect allVisible row label.
indeterminatebooleanfalseWhether only some (not all) options are currently selected — shows a dash instead of a check. Takes precedence over checked for both the glyph and aria-checked="mixed".
disabledboolean—Disables the row.

SelectStickyList

Pads sticky rows in SelectContent's header (a SelectSelectAll + SelectSeparator) with the same inset the scrolling list uses.

PropTypeDefaultDescription
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>—Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render.

SelectFooter

A non-interactive footer pinned below the list (a hint, a count) — the same chrome as MenuFooter. Pass it through SelectContent's footer.

PropTypeDefaultDescription
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>—Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render.