Skip to content
  1. Keyline UI
  2. Select
Keyline UIComponents
  • Get started
    • Installation
    • Theming
    • Modes
    • Configuration
    • Composition
  • Actions
    • Button
    • Button group
    • Split button
    • Toggle
    • Toggle group
    • Toolbar
    • Menu
    • Menubar
    • Context menu
  • Inputs
    • Field and form
    • Checkbox
    • Checkbox group
    • Radio group
    • Switch
    • Slider
    • Segmented
    • Select
    • Native select
    • Combobox
    • Multiselect
    • Number field
    • OTP field
    • Time field
    • Date picker and calendar
    • Date range
  • Data
    • Table
    • Chart
    • Stat and meter
    • Status and badge
    • Progress
    • Skeleton
    • Empty
    • Avatar
    • Kbd
    • Marker
  • Navigation
    • Tabs
    • Breadcrumb
    • Pagination
    • Nav
    • Navigation menu
    • Command menu
  • Overlays
    • Dialog
    • Alert dialog
    • Drawer
    • Sheet
    • Popover
    • Hover card
    • Tooltip
    • Toast
    • Notice
  • Layout
    • App shell
    • Sidebar
    • Panel
    • Resizable
    • Scroll area
    • Accordion
    • Collapsible
    • Carousel
    • Inspector
    • Item
    • Direction
  • Conversation
    • Message
    • Bubble
    • Message scroller
    • Attachment
    • Questionnaire
  • Blocks
    • Shipments

Select

One choice from a list that docks under its field and shares its edge. The chosen option keeps its mark; the row under your cursor is ink. Disabled options can still be read.

Loading the live example…

"use client"

import { useState } from "react"
import { Select, type SelectOption } from "@/components/keyline/ui/select"

const PEOPLE: SelectOption[] = [
  { value: "dwight", label: "Dwight Schrute", description: "41 open accounts", code: "DS", group: "Sales" },
  { value: "jim", label: "Jim Halpert", description: "33 open accounts", code: "JH", group: "Sales" },
  { value: "phyllis", label: "Phyllis Vance", description: "28 open accounts", code: "PV", group: "Sales" },
  { value: "stanley", label: "Stanley Hudson", description: "On a crossword until 3", code: "SH", group: "Sales", disabled: true },
  { value: "michael", label: "Michael Scott", description: "Regional Manager", code: "MS", group: "Management" },
]

export function AssignLead() {
  const [rep, setRep] = useState<string | null>(null)
  const who = PEOPLE.find((p) => p.value === rep)

  return (
    <div className="grid max-w-[360px] gap-3">
      <Select label="Assign the Lackawanna County lead to" placeholder="Choose a rep" options={PEOPLE} value={rep} onValueChange={setRep} />
      <p role="status" className="m-0 min-h-5 text-[14px] text-kl-ink-2">
        {who ? `${String(who.label).split(" ")[0]} has the lead. The county wants a call by Friday.` : "Unassigned since Monday."}
      </p>
    </div>
  )
}

Installation

npx shadcn@latest add @keyline-ui/select

Run it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.

Usage

import { Select } from "@/components/keyline/ui/select"
<Select
  label="Assign the lead to"
  placeholder="Choose a rep"
  options={[
    { value: "dwight", label: "Dwight Schrute", code: "DS" },
    { value: "jim", label: "Jim Halpert", code: "JH" },
  ]}
  value={rep}
  onValueChange={setRep}
/>

Examples

Required

In a Form, required stops the submit and shows error under the field. Choose a weight and the message goes.

Loading the live example…

"use client"

import { useState } from "react"
import { Button } from "@/components/keyline/ui/button"
import { Form, FormActions } from "@/components/keyline/ui/field"
import { Select } from "@/components/keyline/ui/select"

const WEIGHTS = [
  { value: "20", label: "20 lb copy" },
  { value: "24", label: "24 lb premium" },
  { value: "110", label: "110 lb cardstock" },
]

export function QuoteForm() {
  const [sent, setSent] = useState<string | null>(null)

  return (
    <Form className="max-w-[360px]" onFormSubmit={(v) => setSent(`Quote sent with ${WEIGHTS.find((w) => w.value === v.weight)?.label}.`)}>
      <Select name="weight" label="Paper weight" placeholder="Choose a weight" required options={WEIGHTS} error="Choose a weight. The price depends on it." />
      <FormActions>
        <Button type="submit" variant="primary">
          Send quote
        </Button>
      </FormActions>
      <p role="status" className="m-0 min-h-5 text-[14px] text-kl-ink-2">
        {sent}
      </p>
    </Form>
  )
}

Props

PropTypeDefaultDescription
labelReactNodeDefault —Names the field. Required.
optionsSelectOption[]Default —{ value, label, description?, code?, group?, disabled? }. Options with a group are listed under a heading.
valuestring | nullDefault —With onValueChange. Or start with defaultValue.
placeholderReactNodeDefault "Choose…"Shown until something is chosen.
errorReactNodeDefault —The message when a check fails, such as required. With invalid it always shows.
descriptionReactNodeDefault —A line under the field.
layout"control" | "cell"Default "control"cell drops the frame and hides the label, for a select inside another frame.

For rows the options can't describe, compose the parts: SelectRoot, SelectLabel, SelectTrigger, SelectContent, SelectItem, SelectGroup and SelectSeparator. Built on Base UI Select.

Sheet 23 of 73PreviousSegmentedNextNative select
On this page