Skip to content

HierarchicalSearch

Walks the navigation tree level by level, or searches it, and emits the row you pick with the path that reaches it. It is a wrapper over search-control, which owns the debounce and the list.

Terminal window
pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/hierarchical-search.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/hierarchical-search.json
HierarchicalSearch: browse a project, or search it and read the path

React

Loading the React demo…

Svelte

Loading the Svelte demo…

proptypedefaultmeaning
contextSgContextrequiredThe widget context. Every read goes through it, so widgets on a page share one cache.
rootPathstring'/'Where the tree starts. /Project/70 scopes it to that project.
entityTypesstring[] | Record<string, WireCondition[] | null>Shot, Asset, Sequence, TaskTypes a search may end on.
thumbnailstring | false'image'Field holding the thumbnail URL. A row with no picture falls back to its type glyph.
labelFieldstring—Field holding the row label.
subLabelFieldstring | CollectionColumn | nullnullThe muted line under the label. A resolved column renders it by type.
subLabel(row) => string—The muted line of your own. Wins over subLabelField.
secondaryFieldstring | CollectionColumn | nullnullThe right-aligned value, drawn by its data type.
secondary(row) => string—Right-aligned text of your own. Wins over secondaryField.
showCodebooleanfalseShows the row's code beside the label when the two differ.
fieldsstring[][]Extra fields to request, so your own sub-label or secondary can read them.
noMatchLabelstring'No match'Shown when a query matches nothing.
size'sm' | 'md' | 'lg''md'Row text, leading slot and glyphs.
class / classNamestring—Merged after the widget's own classes.
placeholderstring'Search the hierarchy…'Text in the search input.
emptyLabelstring'No rows'Shown when a level holds nothing.
loadingLabelstring'Loading…'Names the skeletons a read stands behind, for a screen reader.
errorLabelstring—Shown in place of what the failed read said.

Every other attribute is spread onto the root: id, aria-*, data-*, key handlers and a ref to the root element.

With no query the list is one level of the tree. With a query it is the rows that match, each shown as the breadcrumb that reaches it, the row itself last and in bold.

A row is the shared picker row: a picture, the label, a muted sub-label and a right-aligned secondary drawn by its data type. A level of the tree carries no picture, so those rows show their type glyph; a searched row shows the thumbnail the second read answered. With no subLabelField and no subLabel, the sub-label is the row’s type, or Group on a level.

entityTypes limits what a search returns. Browsing reaches every level whatever it says; a row that is not one of these types opens instead of being picked.

eventpayloadwhen
onSelectEntityRef, EntityRef[]A row was picked. The second argument is every row its path runs through, root first.

None.

keydoes
Down / UpMoves through the level.
RightOpens the level below the row.
Left / BackspaceGoes back up one level.
ArrowDown / ArrowUpfrom SearchControlMoves the highlight, through a load-more page.
EnterPicks the row, or opens it when it is not a searchable type.
EscapeClears the query.

Backspace goes up only when the query is empty; otherwise it edits the query.

The tree is read one level per call: the answer names the paths of its children and says which of them are worth opening (post_hierarchy_expand).

A path runs through field names, such as sg_sequence between a project’s shots and a sequence, so the shape of the tree is the site’s own navigation configuration rather than a fixed hierarchy (post_hierarchy_search).

Searching does not go through the hierarchy endpoints. hierarchy/_search takes an entity and answers where it sits; its criteria accepts the single key entity and any other key answers search_criteria size must be 1, which counts the keys it recognises rather than the ones sent (post_hierarchy_search). So the words are matched by _text_search and each hit is then asked for its path. That endpoint has no fields parameter either, so the picture and whatever the row props name are a second read of the hits (post_entity_text_search).

The hierarchy endpoints take application/json and refuse the vendor content types every other POST on this API demands (046_search_without_a_path).

The list is one engine in both frameworks: it is always open, always in place and always holds a highlight. It fades at whichever edge has more content past it, holds a gutter for its scrollbar, and carries a live region saying what it is doing. The pattern is coss.com/ui at e937bec, read as a reference and not installed.