Skip to content
  1. Keyline UI
  2. Toggle
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

Toggle

A button that stays pressed. Pressed fills the cell yellow and lights the lamp, so the state has a shape as well as a colour. The label never changes.

Loading the live example…

"use client"

import { useState } from "react"
import { Toggle } from "@/components/keyline/ui/toggle"

const EXPENSES = [
  { who: "Kevin Malone", what: "Cookies for the 3 o’clock meeting", amount: "$14.99", receipt: false },
  { who: "Michael Scott", what: "Dundies trophies (12)", amount: "$186.40", receipt: false },
  { who: "Oscar Martinez", what: "Toner, Staples", amount: "$62.18", receipt: true },
  { who: "Meredith Palmer", what: "Client lunch, Cugino’s", amount: "$48.75", receipt: true },
]

export function ExpenseFilter() {
  const [missingOnly, setMissingOnly] = useState(false)
  const missing = EXPENSES.filter((e) => !e.receipt)
  const rows = missingOnly ? missing : EXPENSES

  return (
    <div className="grid gap-4">
      <Toggle pressed={missingOnly} onPressedChange={setMissingOnly} count={missing.length} className="justify-self-start">
        Missing receipt
      </Toggle>
      <ul className="m-0 grid list-none gap-1 p-0 text-[14px]" aria-label="Expenses this week">
        {rows.map((e) => (
          <li key={e.what} className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4">
            <span className="min-w-0 truncate">
              {e.who} · <span className="text-kl-ink-2">{e.what}</span>
            </span>
            <span className="tabular-nums">{e.amount}</span>
          </li>
        ))}
      </ul>
      <p role="status" className="m-0 text-[14px] text-kl-ink-2">
        {missingOnly ? `${missing.length} expenses Angela can’t approve yet.` : `${EXPENSES.length} expenses this week.`}
      </p>
    </div>
  )
}

Installation

npx shadcn@latest add @keyline-ui/toggle

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

Usage

import { Toggle } from "@/components/keyline/ui/toggle"
<Toggle pressed={missingOnly} onPressedChange={setMissingOnly}>
  Missing receipt
</Toggle>

Examples

Icon

With icon the toggle is a square cell. Name it with aria-label: the name says what pressing does, and aria-pressed says whether it is on.

Loading the live example…

"use client"

import { Pin } from "lucide-react"
import { useState } from "react"
import { Toggle } from "@/components/keyline/ui/toggle"

export function PinClient() {
  const [pinned, setPinned] = useState(true)

  return (
    <div className="flex flex-wrap items-center gap-3">
      <Toggle icon pressed={pinned} onPressedChange={setPinned} aria-label="Pin to my clients">
        <Pin size={16} aria-hidden="true" />
      </Toggle>
      <p role="status" className="m-0 text-[14px] text-kl-ink-2">
        Blue Cross of Pennsylvania {pinned ? "is pinned to the top of Stanley’s clients." : "is back in alphabetical order."}
      </p>
    </div>
  )
}

Props

PropTypeDefaultDescription
pressedbooleanDefault —Controlled state, with onPressedChange. Or start it with defaultPressed.
countReactNodeDefault —A count after the label: how many rows the toggle would show.
iconbooleanDefault falseA square, icon-only toggle; give it an aria-label. Pressed shows a floor keyline instead of the lamp.
layout"control" | "cell"Default "control"cell drops the frame, for a toggle in a panel header or a field frame.

For several independent toggles in one frame, use Toggle group. For one choice of many, use Segmented. Built on Base UI Toggle.

Sheet 10 of 73PreviousSplit buttonNextToggle group
On this page