Tag Input
Installation
npx @mielui/svelte add tag-inputyarn dlx @mielui/svelte add tag-inputbunx @mielui/svelte add tag-inputUsage
Bind tags on Root to the list. Inside Root, List renders the tags and Input takes new ones. Enter or a comma adds the typed text, and Backspace in an empty input removes the last tag.
<script lang="ts">
import * as TagInput from '@mielui/svelte/components/tag-input';
let tags = $state(['svelte']);
</script>
<TagInput.Root bind:tags label="Topics">
<TagInput.List />
<TagInput.Input placeholder="Add a topicโฆ" />
</TagInput.Root>Set name to submit each tag as a hidden form value. A disabled field submits nothing. Bind element on Input to reach the text input.
Examples
Saving topics
A tag field with a count, a clear button, and a save button that reads the current tags.
2 topics
Adding tags
Enter adds the typed text, and so does any character in delimiters, a comma by default. addOnBlur adds what is left in the field when it loses focus, and addOnPaste splits pasted text on the same delimiters. Both are on by default. normalize cleans each tag before it is added. A tag that already exists is refused unless allowDuplicates is set. Bind query to read or set the text still being typed.
Still typing: nothing
Responding to changes
onAdd and onRemove report single tags. onTagsChange reports the whole list.
Validation
Return false or a message from validate to refuse a tag. onReject receives the refused value, a code, and a readable reason.
Maximum
max caps the list. Extra tags are refused with the max-tags code.
Required
required blocks native form submission until there is at least one tag. labels.required sets the message the browser shows.
Labels
Built-in text is English. Pass a labels object to Root to translate the remove button's name, the refusal reasons, the announcements after a tag is added or removed, and the required message. TagInputLabels types it. Every key is optional, and omitted keys keep their English default.
<TagInput.Root
bind:tags
label="Sujets"
labels={{
remove: (tag) => `Supprimer ${tag}`,
duplicate: (tag) => `${tag} est dรฉjร dans la liste.`,
maxReached: (max) => `${max} sujets au maximum.`,
added: (tag, count) => `${tag} ajoutรฉ, ${count} au total.`,
removed: (tag, count) => `${tag} retirรฉ, ${count} au total.`,
required: 'Ajoutez au moins un sujet.'
}}
>
<TagInput.List />
<TagInput.Input placeholder="Ajouter un sujetโฆ" />
</TagInput.Root>API reference
TagInput.Root
Owns tags and draft entry state.
labelsTagInputLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
tagsBindablestring[]Current tags. Bindable.
Default
[]queryBindablestringText in the input. Bindable.
Default
''maxnumberLargest number of tags.
allowDuplicatesbooleanAllows the same tag more than once.
Default
falsedisabledbooleanPrevents interaction and dims the control.
Default
falselabelstringVisible label linked to the control.
descriptionstringSupporting text under the label, announced with the control.
invalidbooleanMarks the field invalid. It defaults to true when there are issues.
issuesreadonly Readonly<{ message: string; }>[]Validation issues shown under the control in place of the description.
Default
[]namestringField name submitted with the form.
requiredbooleanRequires at least one tag for native form submission. Carried by a dedicated validation anchor, since hidden inputs are barred from constraint validation.
Default
falsevariantTagInputVariantoutlinehas a border.secondaryhas a filled background.Default
'outline'validate((tag: string) => string | boolean)Returns true to accept a tag, or a message that explains why it is refused.
normalize((tag: string) => string)Cleans a tag before it is added, such as trimming or lowercasing it.
delimitersstring[]Characters that finish a tag as you type.
Default
[',']addOnBlurbooleanAdds the typed text as a tag when the field loses focus.
Default
trueaddOnPastebooleanSplits pasted text into tags.
Default
trueonTagsChange((tags: string[]) => void)Called with the new list when tags change.
onAdd((tag: string) => void)Called with each tag that is added.
onRemove((tag: string) => void)Called with each tag that is removed.
onReject((rejection: TagInputRejection) => void)Called when a tag is refused, with the reason.
idstringId of the element.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
TagInput.Input
Accepts new tag text.
placeholderstringText shown while there is no value.
Default
'Add a tagโฆ'elementBindableHTMLInputElementBindable reference to the DOM element.
Default
undefinedclassstringClasses added to the element.
TagInput.List
Groups the entered tags.
labelstringAccessible name of the tag list.
Default
'Tags'classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
TagInput.Tag
Renders one tag with its remove control.
valueRequiredstringText of the tag.
indexnumberPosition of the tag in the list.
removablebooleanShows the remove button.
Default
trueonRemove((tag: string) => void)Called with each tag that is removed.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
pnpm dlx @mielui/svelte add tag-input