Context
src/lib/widgets/input/ has a strong primitive set — Combobox, MultiSelect, Search, Textarea, etc. — but no ChipInput: a single-line input that produces a list of chips/tags from free-form text, typically delimited by Enter or comma.
Surfaced during paw-enterprise#220 (calendar event drawer). Attendees was scoped down to a plain text input because no ChipInput exists. The shape comes up across multiple form patterns: attendees, tags, allowed-domains lists, search filter values, mention targets.
What to add
src/lib/widgets/input/ChipInput.svelte — a single primitive that:
- Accepts free-form text in an input field
- Converts to a chip on Enter, comma, or blur (configurable delimiters)
- Renders existing chips inline with the input
- Supports backspace-to-remove last chip when input is empty
- Validates per-chip via an optional
validate(value: string) => string | null (return error or null)
- Supports a max-chips cap
- Exposes
value as string[] (bindable)
API sketch
<script>
let { value = $bindable([]), placeholder = '', delimiters = [',', 'Enter'],
max = Infinity, validate = null, disabled = false } = $props();
</script>
Optional: <ChipInput suggestions={...}> for autocomplete (could route through Combobox if it makes the integration cleaner).
Design considerations
- Match the existing
Input.svelte baseline visual / focus ring
- Chips render via the existing
display/Chip.svelte for consistency
- Keyboard: Enter to commit, Backspace to remove, Tab cycles focus normally
- Accessibility: aria-multiselectable, each chip has its own remove button with label
- Pasted text with delimiters splits into multiple chips
Acceptance
References
- Triggering PR: qbtrix/paw-enterprise#220
- Adjacent:
MultiSelect.svelte (closed set), Combobox.svelte (typeahead), display/Chip.svelte (chip visual)
Context
src/lib/widgets/input/has a strong primitive set — Combobox, MultiSelect, Search, Textarea, etc. — but no ChipInput: a single-line input that produces a list of chips/tags from free-form text, typically delimited by Enter or comma.Surfaced during paw-enterprise#220 (calendar event drawer). Attendees was scoped down to a plain text input because no ChipInput exists. The shape comes up across multiple form patterns: attendees, tags, allowed-domains lists, search filter values, mention targets.
What to add
src/lib/widgets/input/ChipInput.svelte— a single primitive that:validate(value: string) => string | null(return error or null)valueasstring[](bindable)API sketch
Optional:
<ChipInput suggestions={...}>for autocomplete (could route through Combobox if it makes the integration cleaner).Design considerations
Input.sveltebaseline visual / focus ringdisplay/Chip.sveltefor consistencyAcceptance
src/lib/widgets/input/ChipInput.svelteMultiSelect.test.tsshape)src/lib/widgets/input/index.tsvalueworks asstring[]References
MultiSelect.svelte(closed set),Combobox.svelte(typeahead),display/Chip.svelte(chip visual)