Chip Input
Shared label and supporting-text behaviour with catnip-input is summarised on Inputs overview.
Draft input props are forwarded through catnipInput using the same prop names as catnip-input. This follows the composed components convention: parent-owned behaviour stays top-level, child-owned configuration goes under the child namespace.
The draft line is always single-line text. catnip-input-chip reserves these inner input props even if they are supplied in catnipInput: modelValue, type, hideLabel, name, and supportingText. Shared field state (size, intent, disabled, readonly, required) stays top-level so chips, Add, supporting text, and the draft line stay aligned.
Draft line
Committed chips live in modelValue. The draft (uncommitted typing) is separate. How you interact with draft depends on whether you use the default embedded catnip-input or the draftInput slot:
Default embedded catnip-input | Custom draftInput slot | |
|---|---|---|
| Who owns draft | Chip (internal) | Parent |
| Parent sets draft | setDraftValue() on a host ref | .draftValue prop |
| Parent observes draft | @update:draftValue (optional) | Your own binding on the slotted control |
| After Add / Enter commit | Chip clears draft | Parent clears .draftValue in @update:modelValue |
| Enter to commit | Chip handles | Parent handles |
| Configure the field | .catnipInput="{ … }" | You own slotted markup (catnipInput ignored) |
Do not bind .draftValue when using the default input — it is ignored. Use setDraftValue() to prefill, reset, or programmatically change the draft (init on mount, clear after an external action, etc.).
Default embedded input — observe and reset:
<catnip-input-chip
ref="chipRef"
label="Tags"
.modelValue="tags"
.catnipInput="{ placeholder: 'Add a tag' }"
@update:modelValue="tags = $event.detail[0]"
@update:draftValue="draft = $event.detail[0]"
/>
<button type="button" @click="chipRef?.setDraftValue?.('')">Clear draft</button>Custom draftInput slot — parent-controlled draft (see Custom draft input below).
Props
Props are grouped by what you are trying to configure. Chip-input-owned behaviour stays top-level; draft-field-only Input props live under catnipInput.
Value & tag rules
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| modelValue | string[] | [] | — | Committed tags as catnip-chip rows; model-value in HTML / .modelValue in frameworks. Draft text is not included. |
| draftValue | string | "" | — | Custom draftInput slot only. Parent-controlled draft text. Add reads this value; chip does not clear it after commit — parent clears in @update:modelValue. Ignored with the default embedded draft input (use setDraftValue() instead). |
| minChips | number | undefined | — | Minimum committed tag count; chip removal is disabled while the count is at this value (HTML min-chips). |
| maxChips | number | undefined | — | Maximum committed tag count; Add / Enter stop committing new tags once the count reaches this value (HTML max-chips). |
| maxVisibleChips | number | undefined | — | Maximum chips to show before collapsing the rest behind a tertiary Show n more button (HTML max-visible-chips). |
Commit controls
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| showAddButton | boolean | true | — | false hides Add; Enter still commits the draft. |
| addButton | CatnipInputChipAddButtonProps | {} | — | Props forwarded to the embedded Add catnip-button (same pattern as catnipInput). See Add button below. |
| showMoreChipsLabel | string | (i18n inputChip.showMore) | — | Label template for the collapsed tags control. Use {count} for the number of hidden tags (HTML show-more-chips-label). |
| showLessChipsLabel | string | (i18n inputChip.showLess) | — | Label for the expanded tags control that collapses the list again (HTML show-less-chips-label). |
Add button
Same pattern as catnipInput: configure the embedded catnip-button without renaming child prop names. See Button — Specs for every forwardable prop.
Chip-input-reserved keys cannot be forwarded:
typeis always"button"(Add never submits a form).disabledis derived from validation (maxChips, empty / duplicate draft, top-leveldisabled).sizetracks the tag'ssizeso chips, draft, and Add stay aligned.
The synthetic label is the visible button text — catnip-button itself takes label content via its default slot, so this field lives on the wrapper instead. Everything else (appearance, purpose, leftIcon, rightIcon, intent, ariaLabel, loading, name, value, form, autofocus, testSelectors) forwards as-is and defaults to appearance: "secondary", purpose: "utility", leftIcon: "plus".
<catnip-input-chip
label="Tags"
.modelValue="tags"
.addButton="{
label: 'Add tag',
ariaLabel: 'Add tag to list',
appearance: 'primary',
leftIcon: 'plus-circle'
}"
/>Field presentation
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| label | string | "" | — | Visible label text when the label slot is empty. |
| optional | boolean | false | — | Optional hint when not required. |
| optionalText | string | "" | — | Overrides optional hint (HTML optional-text). |
| info | string | "" | — | Info tooltip text on the label (info wins over label.suffix when both are set). |
| alignment | string | "left" | left, center, right | Label row alignment. |
| requiredMarker | string | "*" | — | Visual required marker when required (HTML required-marker). |
| requiredScreenReaderText | string | "" | — | Screen-reader-only supplement when required (HTML required-screen-reader-text). |
| supportingText | string | string[] | { text, intent?, icon? } | { text, intent?, icon? }[] | Supporting copy rendered below the chip list; draft aria-describedby still includes it when present. See Inputs overview — Multiple supporting messages. |
State
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| size | string | "m" | s, m, l | Dimensions / typography on the draft input, chips, and tag controls. |
| intent | string | "neutral" | neutral, warning, danger, success | Status styling on the draft input and supporting text; danger sets aria-invalid on the draft. |
| disabled | boolean | false | — | Disables the draft, Add, chip remove, and draft clear affordance where applicable. |
| readonly | boolean | false | — | Read-only draft and chips where supported. |
| required | boolean | false | — | Native required state on the draft input and label marker state. |
Draft input
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| catnipInput | CatnipInputControlProps | {} | — | Props forwarded to the default embedded catnip-input draft field. Ignored when the draftInput slot is used. |
Common catnipInput values include id, placeholder, autocomplete, autofocus, spellcheck, leftIcon, rightIcon, rightIconClickable, rightIconButtonAriaLabel, showClearButton, clearButtonAriaLabel, maxlength, pattern, ariaLabel, ariaDescribedby, and testSelectors. Extra ariaDescribedby ids are appended to the draft input alongside the generated supporting-text id when supportingText is set.
<catnip-input-chip
label="Tags"
.modelValue="tags"
.catnipInput="{
placeholder: 'Add a tag',
leftIcon: 'search',
showClearButton: true
}"
/>Advanced
| Prop | Type | Default | Options | Description |
|---|---|---|---|---|
| testSelectors | object | See Test selectors | — | data-test overrides for the host, supporting text, Add, Show more, and Show less (see Test selectors below). |
Slots
Label row
| Name | Purpose |
|---|---|
| label | Replaces label prop content; richer markup inside the label element (same pattern as catnip-input). |
| label.action | Trailing action in the label row (slot action on the internal label row). |
| label.suffix | Slot suffix on the internal label — custom markup; info wins when non-empty. |
Draft input adornments
| Name | Purpose |
|---|---|
| draftInput | Replaces the default embedded draft input with any markup. Bind .draftValue from the parent; catnipInput does not apply. |
| catnipInput.leftIconSlot | Forwarded leading icon slot for the default embedded catnip-input draft line. |
| catnipInput.rightIconSlot | Forwarded trailing icon slot for the default embedded catnip-input draft line. |
Custom draft input (draftInput slot)
When draftInput is set, the parent fully controls draft text via .draftValue. The chip uses that prop for Add disabled / duplicate checks and to commit on Add click. It does not clear draft after commit — clear .draftValue in your @update:modelValue handler.
- Enter to commit — not handled by the chip in slot mode; wire Enter in your slotted control if needed (often by calling the same logic as Add).
- Double-click chip to edit — chip emits
update:draftValuewith the chip text; set your draft ref from that event and focus your control if needed.
<catnip-input-chip
.modelValue="tags"
.draftValue="draft"
@update:modelValue="onChips"
>
<input
slot="draftInput"
type="text"
placeholder="Add a tag"
.value="draft"
@input="draft = $event.target.value"
/>
</catnip-input-chip>
<script setup>
import { ref } from "vue";
const tags = ref([]);
const draft = ref("");
function onChips(e) {
tags.value = e.detail[0];
draft.value = ""; // parent clears after commit
}
</script>Methods
For the default embedded draft input only. When the draftInput slot is used, bind .draftValue instead — setDraftValue() logs a dev warning and has no effect.
| Method | Description |
|---|---|
setDraftValue(value: string) | Set or reset the draft line on the default embedded catnip-input. Does not commit a chip. Typical uses: prefill on mount, clear from a parent button, reset after a side action. Use a host ref (same pattern as catnip-tooltip reposition()). |
<template>
<catnip-input-chip
ref="chipRef"
label="Tags"
.modelValue="tags"
@update:modelValue="onChips"
@update:draftValue="onDraft"
/>
<button type="button" @click="prefillDraft">Prefill draft</button>
<button type="button" @click="clearDraft">Clear draft</button>
</template>
<script setup>
import { onMounted, ref } from "vue";
const chipRef = ref(null);
const tags = ref([]);
const draft = ref("");
function onChips(e) {
tags.value = e.detail[0];
}
function onDraft(e) {
draft.value = e.detail[0]; // optional — observe chip-owned draft
}
function prefillDraft() {
chipRef.value?.setDraftValue?.("prefilled");
}
function clearDraft() {
chipRef.value?.setDraftValue?.("");
}
onMounted(() => {
chipRef.value?.setDraftValue?.("edit me"); // optional init
});
</script>Events
| Name | Payload | Description |
|---|---|---|
update:modelValue | string[] | New tags array after a chip is added or removed. |
update:draftValue | string | Default embedded input: emitted when draft changes (typing, clear after commit, chip double-click edit, or setDraftValue()). Optional to listen — you do not need to write back. draftInput slot: emitted on chip double-click edit so the parent can set .draftValue. |
Forms
The name you set on <catnip-input-chip> is what participates in traditional form serialization (along with form if used). The submitted value is the committed tags joined with commas (see below). The inner draft <input> uses an empty name so the unsent line is never submitted.
For ElementInternals / attachInternals, the host’s form value is updated when the component emits update:modelValue (same comma-joined string). Draft text is never included.
Test selectors
General guidance for role-based keys, repeated children, and nested forwarding lives in Component API — Test selectors (see Multiple subcomponents of the same type).
Chip-input-owned pieces accept a flat string that becomes that element's data-test. Composed children accept either a flat string (used as the child's root) or a nested object that is forwarded as the child's full testSelectors — same convention as catnipInput prop forwarding.
| Key | Default data-test | Type |
|---|---|---|
root | catnip-input-chip | string |
draftRow | catnip-input-chip-draft-row | string |
chips | catnip-input-chip-chips | string |
supportingText | catnip-input-supporting-text | string |
addButton | catnip-input-chip-add | string or CatnipButton selectors object |
showMoreButton | catnip-input-chip-show-more | string or CatnipButton selectors object |
showLessButton | catnip-input-chip-show-less | string or CatnipButton selectors object |
catnipInput | (uses CatnipInput defaults) | CatnipInput selectors object — forwarded to the draft input |
.testSelectors="{
root: 'permissions-tag',
addButton: 'permissions-add',
catnipInput: {
leftAdornment: 'permissions-left-adornment'
}
}"