Option List
tool-ui/option-listFreeBlock
Single or multi-select choices with confirmation actions.
See it running
Open the demo on tool-ui
www.tool-ui.com/components/option-listInstall it
npx shadcn@latest add https://www.tool-ui.com/r/option-list.jsonSource
1"use client";23import {4 useMemo,5 useState,6 useCallback,7 useEffect,8 useRef,9 Fragment,10} from "react";11import type { KeyboardEvent } from "react";12import type {13 OptionListProps,14 OptionListSelection,15 OptionListOption,16} from "./schema";17import {18 normalizeSelectionForOptions,19 parseSelectionToIdSet,20} from "./selection";21import { ActionButtons } from "../shared/action-buttons";22import { normalizeActionsConfig } from "../shared/actions-config";23import type { Action } from "../shared/schema";24import { cn, Button, Separator } from "./_adapter";25import { Check } from "lucide-react";2627function convertIdSetToSelection(28 selected: Set<string>,29 mode: "multi" | "single",30): OptionListSelection {31 if (mode === "single") {32 const [first] = selected;33 return first ?? null;34 }35 return Array.from(selected);36}3738function areSetsEqual(a: Set<string>, b: Set<string>) {39 if (a.size !== b.size) return false;40 for (const val of a) {41 if (!b.has(val)) return false;42 }43 return true;44}4546interface SelectionIndicatorProps {47 mode: "multi" | "single";48 isSelected: boolean;49 disabled?: boolean;50}5152function SelectionIndicator({53 mode,54 isSelected,55 disabled,56}: SelectionIndicatorProps) {57 const shape = mode === "single" ? "rounded-full" : "rounded";5859 return (60 <div61 className={cn(62 "flex size-4 shrink-0 items-center justify-center border-2 transition-colors",63 shape,64 isSelected && "border-primary bg-primary text-primary-foreground",65 !isSelected && "border-muted-foreground/50",66 disabled && "opacity-50",67 )}68 >69 {mode === "multi" && isSelected && <Check className="size-3" />}70 {mode === "single" && isSelected && (71 <span className="size-2 rounded-full bg-current" />72 )}73 </div>74 );75}7677interface OptionItemProps {78 option: OptionListOption;79 isSelected: boolean;80 isDisabled: boolean;81 selectionMode: "multi" | "single";82 isFirst: boolean;83 isLast: boolean;84 onToggle: () => void;85 tabIndex?: number;86 onFocus?: () => void;87 buttonRef?: (el: HTMLButtonElement | null) => void;88}8990function OptionItem({91 option,92 isSelected,93 isDisabled,94 selectionMode,95 isFirst,96 isLast,97 onToggle,98 tabIndex,99 onFocus,100 buttonRef,101}: OptionItemProps) {102 const hasAdjacentOptions = !isFirst && !isLast;103104 return (105 <Button106 ref={buttonRef}107 data-id={option.id}108 variant="ghost"109 size="lg"110 role="option"111 aria-selected={isSelected}112// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tool-ui
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Approval Cardapproval-card | tool-ui | Blocks | Free | 2 deps · 11 files | |
| Audioaudio | tool-ui | Blocks | Free | 2 deps · 9 files | |
| Chartchart | tool-ui | Blocks | Free | 2 deps · 8 files | |
| Citationcitation | tool-ui | Blocks | Free | 2 deps · 15 files | |
| Code Blockcode-block | tool-ui | Blocks | Free | 3 deps · 11 files | |
| Code Diffcode-diff | tool-ui | Blocks | Free | 3 deps · 10 files | |
| Data Tabledata-table | tool-ui | Blocks | Free | 1 dep · 17 files | |
| Geo Mapgeo-map | tool-ui | Blocks | Free | 4 deps · 12 files |
