Selection List
Compact list of selected items with removable or read-only rows and composable content.
Use SelectionList with SelectionListItem for selected people, teams, or orgs in a compact list. They render accessible div elements with list roles. SelectionList owns the card background, scroll area, border, radius, and row dividers; children own the leading row content. Pass badges or other end-aligned content through trailing. Pass onRemove and removeAriaLabel when the row can be removed; omit both for a read-only row. Do not use ListItem here; that composite is the heavier event-type / workflow card row.
Use the components directly for ordinary lists. No virtualization setup is needed: the list uses a max-height COSS ScrollArea with an edge fade by default. HostSelect adds virtualization only when it has more than 100 selected hosts; that optimization belongs to the consumer, not this composite.
import { SelectionList, SelectionListItem } from "@coss/ui/shared/selection-list";Example
HostSelect selected-host list below the virtualization threshold: divided bordered container, priority badge on a round-robin host, close on every row.
<div className="mt-3 mb-4">
<SelectionList>
<SelectionListItem
onRemove={() => remove(option)}
removeAriaLabel={`Remove ${option.label}`}
trailing={
<Badge size="sm" variant="outline">
{priorityLabel}
</Badge>
}>
<Avatar className="size-5">
{option.avatar ? <AvatarImage alt={option.label} src={option.avatar} /> : null}
<AvatarFallback className="text-[.625rem]">{initials}</AvatarFallback>
</Avatar>
<span className="min-w-0 flex-1 truncate font-medium">{option.label}</span>
</SelectionListItem>
</SelectionList>
</div>Set scrollable={false} only when the list should grow with its content or a parent already owns scrolling. For unusually large lists, consumers may pass native ref and style props to the list and position virtualized items themselves, as HostSelect does.
API
| Prop / part | Type | Notes |
|---|---|---|
SelectionList | ComponentProps<"div"> | Accessible list container that owns the border and radius. |
SelectionListItem | ComponentProps<"div"> | Selected item; renders a trailing remove control when onRemove is provided. |
scrollable | boolean | Wraps the list in a max-height COSS ScrollArea. Defaults to true. |
children | ReactNode | Leading row content. |
trailing | ReactNode | Optional end-aligned content before the close control. |
onRemove | () => void | Optional close control click. When provided, removeAriaLabel is required. |
removeAriaLabel | string | Accessible name required with onRemove. |
SelectionList className | string | Applied to the inner list div. |
SelectionListItem className | string | Applied to the item div. |
…div props | ComponentProps<"div"> | Native props such as ref, style, and data-index. |
Call sites
| File | Notes |
|---|---|
apps/web/modules/event-types/components/host-select.tsx | Selected hosts on the Assignment tab |
apps/web/modules/events/components/tabs/hosts-tab.tsx | Event editor host roster and external co-hosts |
apps/web/modules/ee/organizations/new/_components/AddNewTeamsForm.tsx | Removable teams entered during organization onboarding |
apps/web/modules/ee/organizations/new/_components/OnboardMembersView.tsx | Removable invited members and read-only migrating members |
Example URLs
Not exhaustive — a few places you can open locally (e.g. http://localhost:3000) to see this in product.
| Path | Notes |
|---|---|
/event-types/<id>?tabName=team | Assignment tab — selected host rows |
/settings/organizations/new/onboard-members | Organization onboarding — pending and migrating members |
Source
On This Page