StatusPicker
Picks one status code for an entity type, offering only the codes the project it is scoped to allows.
It is the list picker configured with a status row and a badge for its value: the same control, popup, press rule and keyboard as every other picker.
Single and multi: StatusMultiPicker takes several codes.
Install
Section titled “Install”pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/status-picker.jsonpnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/status-picker.jsonReact
Loading the React demo…
Svelte
Loading the Svelte demo…
| prop | type | default | meaning |
|---|---|---|---|
context | SgContext | required | The widget context. The options and the status table are read through it, once per page. |
entityType | string | required | The type whose status field is offered. |
projectId | number | — | Offer the codes this project allows. |
projectIds | number[] | — | Offer the codes every one of these projects allows. |
field | string | status field | A list or status field other than the type's own. |
value | string | null | null | The selected code, or null when nothing is chosen. bind:value in Svelte, value with onValueChange in React. |
placeholder | string | 'Select a status' | Shown with no selection. |
emptyLabel | string | 'No rows' | Shown when the field offers nothing. |
loadingLabel | string | 'Loading…' | Names the skeletons a read stands behind, for a screen reader. |
errorLabel | string | — | Shown in place of what the failed read said. |
clearable | boolean | the field | Offers a control that clears the value. Unset, it follows the field: a mandatory one is never clearable. |
readonly | boolean | false | Keeps full contrast and drops the chevron, the popup and the clear control. |
disabled | boolean | false | Greys the control and takes it out of the tab order. |
invalid | boolean | false | Sets aria-invalid and the destructive ring. |
showCode | boolean | true | Draws the code as a row's right-aligned secondary, when it says more than the label. |
secondary | (option) => string | the code | A row's right-aligned value, of the caller's own making. |
subLabel | (option) => string | — | The muted line under a row's label. |
siteUrl | string | the context's | Passed to every badge, for a sprite cell outside the status icon set. |
size | 'sm' | 'md' | 'lg' | 'md' | Control height: 7, 8 and 9. |
open | boolean | false | Whether the popup is showing. Two-way in Svelte. |
class / className | string | — | Merged after the widget's own classes. |
Every other attribute is spread onto the root: id, aria-*, data-*, key handlers and a
ref to the root element.
A row is the row anatomy of the design rules: the status icon as the leading mark, the display name as
the row’s text, and the code right-aligned. It is what the filter bar draws
for a status facet, so a page listing statuses twice lists them the same way. A status has one display
name and one icon, so the row’s labelField and thumbnail are fixed, and it has no fields of its
own, so its secondary is a function rather than a field name. The control keeps the badge, where a
status is a value rather than an option.
Without a project the options are the site vocabulary, which hides nothing. projectIds offers the
intersection of what each project allows, in the first project’s order.
The clear control follows the field. Left unset, clearable reads the field’s schema, and a field
the site flags mandatory offers no clear, since clearing it writes a value the site refuses. Set it
and your answer stands, except that a mandatory field is never clearable.
The root carries the size and, while the options load, data-loading.
Events
Section titled “Events”| event | payload | when |
|---|---|---|
onValueChange | string | null | A status was chosen, or the clear control was pressed. |
onOpenChange | boolean | The popup opened or closed. |
onValueChange fires with the code, or with null when the selection is cleared. It also fires
once with null when a new option set drops the selected code, which is what a project change
does.
onOpenChange fires when the popup opens or closes. Svelte also binds it with bind:open.
None. The rows are the shared picker row; the closed state is a status badge.
Keyboard
Section titled “Keyboard”| key | does |
|---|---|
| Space, Enter, ↓ | Opens the list |
| ↑ ↓ | Moves the highlight |
| Enter | Selects the highlighted status and closes |
| Backspace | In an empty search box, clears the status |
| Esc | Closes and keeps the selection |
| Tab | Leaves the control, or reaches the clear control when there is one |
API behaviour
Section titled “API behaviour”A project’s usable statuses are valid_values minus hidden_values, read with project_id.
valid_values is the site’s whole vocabulary and is byte-identical at every scope, so reading it
alone tells you nothing about a project (probe 009).
REST does not enforce hidden_values on write: a hidden status writes and reads back. Subtracting is
right for offering a choice and wrong for testing a row, so a code outside the option set still
renders here, as itself, and stays removable (field_types/status_list).
Labels come from display_values, and a missing key falls back to the raw code rather than dropping
the option (probe 009).
Status lists are per entity type: Version and Task overlap on five codes only, so the options are read per type and per field (probe 009).
Project’s status field is sg_status, a plain list rather than a status_list. There is no Status
row behind a list, so those options carry no icon and no colour (entity_types/Project).