Search field
In reviewLive · web
com.dizyx.nockerl.design.components.NockerlSearchField
Live search: type to filter, Enter submits, ✕ / Esc clears
⌘K
nockerl-design · docs siteStreaming · 2 tools running
api-server · gateway refactorIdle · last active 12m ago
credential-store · allowlist auditNeeds attention · approval required
dueydo · failed deployError · build exited 1
nockerl-voice · dictation historyIdle · macOS menu bar
nockerl-dashboard · inbox syncStreaming · push delivered
Variants: shortcut hint, pill shape, compact toolbar size
⌘K
/
Recents, loading & disabled. Focus the first to see recent searches
Filtering 6 of 6 sessions · submitted 0 times. The island is live.
// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform. Spec + live demo,// not yet exported from @dizyx/nockerl-react; promotion is tracked.)
export function SessionFilter() { const [query, setQuery] = useState(''); const results = sessions.filter((s) => s.name.toLowerCase().includes(query.toLowerCase()));
return ( <> <SearchField label="Search sessions" value={query} onValueChange={setQuery} // filters in place on every keystroke onSubmit={runSearch} // explicit submit on Enter placeholder="Search sessions…" shortcut="⌘K" // inline key hint; Esc / the ✕ clears recents={recentQueries} // optional dropdown when focused + empty onPickRecent={setQuery} /> {results.length === 0 ? <NoMatches query={query} /> : <SessionList rows={results} />} </> );}// (com.dizyx.nockerl.design on GitHub Packages Maven). Magnifier leading (built in) + the// clear (✕) trailing when non-empty (built in), on the shared recessed-well treatment.// No visible label by convention, so the accessible name is `contentDescription`.import com.dizyx.nockerl.design.components.NockerlSearchField
var query by rememberSaveable { mutableStateOf("") }val results = sessions.filter { it.name.contains(query, ignoreCase = true) }
NockerlSearchField( value = query, onValueChange = { query = it }, // filters in place placeholder = "Search sessions", // also the default accessible name contentDescription = "Search sessions", // the required a11y name (no visible label) onSearch = ::runSearch, // ImeAction.Search / keyboard submit enabled = true, loading = isSearching, // swaps the ✕ for a 16dp progress spinner)// macOS / iOS: SwiftUI, from the NockerlDesign package (the parity twin// of this canon; Voice's hand-rolled HistoryView field retires on adoption).// Magnifier + recessed field-well + a clear that shows only when non-empty; the// query + placeholder render the REAL Outfit face (via .nockerlType, ).import NockerlDesign
NockerlSearchField( text: $search, placeholder: "Search transcriptions", accessibilityLabel: "Search history", onSubmit: { query in runSearch(query) } // optional: Enter / the search key).disabled(isBusy) // enablement flows from the environment (platform-idiomatic)
// Async source in flight → the trailing slot shows a spinner instead of the clear:NockerlSearchField(text: $query, loading: isFetching)
// Filtered in place; the empty state mirrors ContentUnavailableView("No matches").let filtered = search.isEmpty ? records : records.filter { $0.text.localizedCaseInsensitiveContains(search) }Parameters
Section titled “Parameters”| Prop | Type | Default | Description |
|---|---|---|---|
label * | string | Accessible name for the searchbox (there is no persistent visible label). Sets aria-label. | |
value * | string | Current query (controlled). | |
onValueChange | (value: string) => void | Fires on every keystroke; the host filters its content live. | |
onSubmit | (value: string) => void | Fires on Enter with the current query (explicit submit). | |
placeholder | string | 'Search…' | Ghost prompt inside the well, supplementary and never the label. |
shape | 'control' | 'pill' | 'control' | 12px control rectangle (default) or full-stadium pill for toolbars / the input bar. |
size | 'md' | 'sm' | 'md' | Control height: md (44px) or a compact sm (36px) for dense toolbars. |
shortcut | string | Inline keyboard hint pinned right (e.g. ⌘K or /). Hidden once the query is non-empty. | |
loading | boolean | false | Shows the searching spinner and sets aria-busy (async source in flight). |
disabled | boolean | false | Inert and clearly seen (never faded to invisible). |
recents | string[] | Recent searches; when focused + empty they drop under the field (arrow-navigable). | |
onPickRecent | (value: string) => void | Replay a recent query (the row sets the value + runs the search; it never selects a value). |
| Parameter | Type | Default | Description |
|---|---|---|---|
value * | String | Current query. | |
onValueChange * | (String) -> Unit | Invoked on every edit; filter in place. | |
modifier | Modifier | Modifier | External modifier. Pass Modifier.fillMaxWidth() for a toolbar-width field. |
placeholder | String | "Search" | Ghost prompt inside the well; also the default contentDescription. |
contentDescription | String | placeholder | The field's accessible name, required by convention since search fields carry no visible label. |
onSearch | (() -> Unit)? | null | Optional explicit-submit callback (ImeAction.Search). |
enabled | Boolean | true | When false, the well is dimmed (alpha) and non-interactive. |
loading | Boolean | false | Swaps the built-in ✕ clear for a 16dp CircularProgressIndicator while an async source is in flight. |
shape | Shape | NockerlControlShape | The 12dp control shape (default). Pass NockerlPillShape ONLY for the toolbar / input-bar idiom (pills are reserved, law §4). |
The magnifier (leading) and the ✕ clear (trailing, shown when the query is non-empty) are built in. There are no icon slots to pass; the field is self-contained.
NockerlSearchField is the packaged twin: the recessed .nockerlFieldWell()
chrome, a decorative leading magnifier, and an interactive trailing clear
(NockerlIconButton, flat glyph) that shows only when non-empty. The query is a
Binding; enablement flows from the environment (.disabled(_:)).
| Parameter | Type | Default | Description |
|---|---|---|---|
text * | Binding<String> | The current query (two-way); filters in place on every keystroke. (The SwiftUI controlled-input idiom for the canon’s value + onChange.) | |
placeholder | String | "Search" | Hint text, and the default accessible name (search fields carry no visible label). |
accessibilityLabel | String? | nil | The field’s accessible name; defaults to placeholder (law §14 persistent name). |
loading | Bool | false | Render a small accent spinner in the trailing slot (an async source in flight) in place of the clear. |
onSubmit | ((String) -> Void)? | nil | Optional explicit submit (Enter / the search key) handed the current query. |
.disabled(_:) | modifier | Enablement flows from the SwiftUI environment (the canon’s enabled), not a parameter. Disabled dims to 55%. |