Skip to content

ProjectPicker

Searches projects on the server, showing each one’s thumbnail and status.

Single and multi: ProjectMultiPicker takes several projects.

Terminal window
pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/project-picker.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/project-picker.json

The item installs the single picker alone. A caller who installed it for ProjectMultiPicker takes the project-multi-picker item instead; this note stands for one release.

ProjectPicker: archived projects, hydration, sizes, states

React

Loading the React demo…

Svelte

Loading the Svelte demo…

proptypedefaultmeaning
includeArchivedbooleanfalseOffer projects whose archived checkbox is set.
contextfrom EntityPickerSgContextrequiredThe widget context. Every read goes through it, so widgets on a page share one cache.
valuefrom EntityPickerEntityRef | nullnullThe chosen row. Two-way in Svelte.
labelFieldfrom EntityPickerstringdisplay-name chainField holding the row label.
searchFieldsfrom EntityPickerSearchFieldSpec[] | ((query) => SearchFieldSpec[])—Fields matched on top of the display-name chain. A function is called with the query.
secondaryFieldfrom EntityPickerstring | CollectionColumn | nullnullField shown right-aligned, drawn by its data type. A resolved column renders it by type.
secondaryfrom EntityPicker(row) => string—Right-aligned text of your own. Wins over secondaryField.
subLabelFieldfrom EntityPickerstring | CollectionColumn | nullnullField shown under the label, drawn by its data type: a status reads its display name.
subLabelfrom EntityPicker(row) => stringthe type, when several are searchedComputes the sub-label.
thumbnailfrom EntityPickerstring | false'image'Field holding the thumbnail URL. false hides the leading slot.
roundThumbnailfrom EntityPickerbooleanfalseDraws the thumbnail as a circle.
showCodefrom EntityPickerbooleanfalseShows the row's code beside the label when the two differ.
siteUrlfrom EntityPickerstringthe context'sThe site the status sprite is served from, for a secondary that is a status.
fieldsfrom EntityPickerstring[]—Extra fields to request.
filtersfrom EntityPickerFilterGroup | WireGroup | nullnullPre-filter, merged into every search with and.
projectIdfrom EntityPickernumber—Scopes to one project.
excludefrom EntityPickerEntityRef[]—Rows kept out of the results.
minQueryLengthfrom EntityPickernumber0Under it the query carries no name condition.
pageSizefrom EntityPickernumber20Rows a page, with a load more row under them.
debounceMsfrom EntityPickernumber250Wait after the last keystroke before searching.
class / classNamefrom EntityPickerstring—Merged after the widget's own classes.
sizefrom PickerControl'sm' | 'md' | 'lg''md'Control height: 7, 8 and 9.
disabledfrom PickerControlbooleanfalse
readonlyfrom EntityPickerbooleanfalseKeeps full contrast and drops the affordances.
invalidfrom EntityPickerbooleanfalseSets aria-invalid and the destructive ring.
clearablefrom EntityPickerbooleantrueShows the clear control.
placeholderstring'Search for a project'Shown in the control while nothing is chosen.
searchPlaceholderfrom EntityPickerstring'Search…'Shown in the query input once something is chosen.
openfrom PickerControlbooleanrequiredReact: whether the popup is showing.
openfrom PickerControlbooleanfalseSvelte: whether the popup is showing, two-way.
emptyLabelfrom EntityPickerstring'No match'Shown when a query matches nothing.
loadingLabelfrom EntityPickerstring'Loading…'Names the skeletons a read stands behind, for a screen reader.
errorLabelfrom EntityPickerstring—Shown in place of what the failed read said.

The sub-label is the project’s status, so an active project can be told from a bidding one.

eventpayloadwhen
onValueChangeEntityRef | null, PickerRow | nullThe selection changed.
onErrorfrom EntityPickerErrorA read failed. The list shows it inline as well.
onOpenChangefrom EntityPickerbooleanThe popup opened or closed. Svelte also binds it with bind:open.

None.

keydoes
any textfrom EntityPickerOpens the list and searches the server.
Enter, Spacefrom EntityPickerOn the chevron, opens the list.
Up, Downfrom EntityPickerMoves the highlight through the rows and keeps it in view, including across a load more page. The last row holds it rather than wrapping.
ArrowDown / ArrowUpfrom PickerControlMoves the highlight, and the list scrolls it into view.
Enterfrom EntityPickerChooses the highlighted row, or loads the next page on the load more row.
Escapefrom EntityPickerCloses the list and clears the query. On a closed picker it does nothing.
Backspacefrom EntityPickerIn an empty search box, clears the value.
ArrowLeft / ArrowRightfrom PickerControlOn a chip, walks the row. ArrowRight past the last chip returns to the input.
Deletefrom PickerControlOn a chip, removes it and leaves the caret on its neighbour.
Tabfrom EntityPickerMoves to the clear control, then the chevron, then out.

Project’s status field is sg_status, a plain list with no Status row behind it, where every other type uses sg_status_list (entity_types/Project).

sg_status is not a liveness filter and is null on most projects; archived, is_template and is_demo are the discriminators, which is why hiding archived projects filters on archived (018_project_listing).

Project is site-wide and has no project field, so projectId adds nothing on this picker.

The row, chip and checkbox anatomy follows shadcn’s Base UI Combobox, read through shadcn 4.21.0. The primitive underneath is Base UI Combobox 1.8.0 in React and Bits UI Combobox 2.19.1 in Svelte. shadcn-svelte ships no combobox item, so each widget composes the headless primitive of its framework and both draw the same rows, the same classes and the same states.