Tags Input

Render tags inside an input, followed by an actual text input.

Svelte
Typescript

Features

  • Type in the input and press enter to add tags
  • Delete tags
  • Disable everything or disable specific tags
  • Option to only allow unique tags
  • Keyboard navigation

Anatomy

  • Root: The root container for the tags input
  • Tag: The tag container for an individual tag
  • Delete Trigger: The button container, to delete an individual tag
  • Edit: An edit container, to edit an individual tag
  • Input: The input textbox for adding new tags

Usage

Use the createTagsInput builder function.

See API Reference > createTagsInput for all available props.
    <script lang="ts">
  import { createTagsInput, melt } from '@melt-ui/svelte'
  const {
    /* ... */
  } = createTagsInput()
</script>
	
    <script lang="ts">
  import { createTagsInput, melt } from '@melt-ui/svelte'
  const {
    /* ... */
  } = createTagsInput()
</script>
	

Use the return values to construct a tags-input.

    <script lang="ts">
  import { createTagsInput, melt } from '@melt-ui/svelte'
 
  // This is a subset of return values
  const {
    elements: { root, input, tag, deleteTrigger, edit },
    states: { tags }
  } = createTagsInput()
</script>
 
<div use:melt={$root}>
  {#each $tags as t}
    <div use:melt={$tag(t)}>
      <span>{t.value}</span>
      <button use:melt={$deleteTrigger(t)}>x</button>
    </div>
    <div use:melt={$edit(t)}>{t.value}</div>
  {/each}
  <input use:melt={$input} type="text" />
</div>
	
    <script lang="ts">
  import { createTagsInput, melt } from '@melt-ui/svelte'
 
  // This is a subset of return values
  const {
    elements: { root, input, tag, deleteTrigger, edit },
    states: { tags }
  } = createTagsInput()
</script>
 
<div {...$root} use:root>
  {#each $tags as t}
    <div {...$tag(t)} use:tag>
      <span>{t.value}</span>
      <button {...$deleteTrigger(t)} use:deleteTrigger>x</button>
    </div>
    <div {...$edit(t)} use:edit>{t.value}</div>
  {/each}
  <input {...$input} use:input type="text" />
</div>
	

Adding a tag

An add function may be passed into the builder. It is called and awaited prior to adding the tag to the $tags store.

It provides you the ability to validate the input value, set a custom id, for example from a backend or 3rd-party API, or update the value to always be uppercase, lowercase, etc.

The function definition is:

    fn: (tag: string) => Tag | string | Promise<Tag | string>
	
    fn: (tag: string) => Tag | string | Promise<Tag | string>
	

whereby tag is the input value.

A tag is an object that consists of an id and value

On resolve, if a string is returned, an id will be internally generated. The same happens when a Tag without an id is returned.

On reject or error, the input is invalidated and not added to the store.

The following example sets the id via a third-party API call and forces the tag to always be uppercase.

    <script lang="ts">
  import { createTagsInput } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    add: async (v: string) => {
      const response = await fetch('https://www.uuidtools.com/api/generate/v1')
 
      if (!response.ok) throw new Error('HTTP error ' + response.status)
 
      const data = await response.json()
      if (!Array.isArray(data) || data.length < 1) {
        throw new Error('Failed to get id')
      }
 
      return { id: data[0], value: v.toUpperCase() }
    }
  })
</script>
	
    <script lang="ts">
  import { createTagsInput } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    add: async (v: string) => {
      const response = await fetch('https://www.uuidtools.com/api/generate/v1')
 
      if (!response.ok) throw new Error('HTTP error ' + response.status)
 
      const data = await response.json()
      if (!Array.isArray(data) || data.length < 1) {
        throw new Error('Failed to get id')
      }
 
      return { id: data[0], value: v.toUpperCase() }
    }
  })
</script>
	

Updating a tag

An update function may be passed into the builder. It is called and awaited prior to updating a tag in $tags store, following an edit.

It provides the ability do something before a tag is updated, such as updating the value in a backend database, setting a new id, or simply manipulating the value to be added.

The function definition is:

    fn: (tag: Tag) => Tag | Promise<Tag>.
	
    fn: (tag: Tag) => Tag | Promise<Tag>.
	
A tag is an object that consists of an id and value

tag.value will be the new (edited) value, while tag.id will be the existing id.

On reject or error the tag is not updated.

The following example uses the existing id and sets the value to uppercase

    <script lang="ts">
  import { createTagsInput, type Tag } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    update: async (tag: Tag) => {
      return { id: tag.id, value: tag.value.toUpperCase() }
    }
  })
</script>
	
    <script lang="ts">
  import { createTagsInput, type Tag } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    update: async (tag: Tag) => {
      return { id: tag.id, value: tag.value.toUpperCase() }
    }
  })
</script>
	

Removing a tag

An asynchronous remove function may be passed into the builder. It is called and awaited prior to removing the tag from the $tags store.

It provides the ability do something before the tag is removed from $tags store, such as deleting the tag from a backend database.

The function definition is:

    fn: (tag: Tag) => boolean | Promise<boolean>
	
    fn: (tag: Tag) => boolean | Promise<boolean>
	

whereby tag is the tag to be removed from the $tags store.

A tag is an object that consists of an id and value

On reject, error or false, the tag is not removed from the store.

The following example disallows a tag with the value one to be deleted.

    <script lang="ts">
  import { createTagsInput, type Tag } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    tags: ['one', 'two'],
    remove: async (t: Tag) => {
      if (t.value === 'one') return false
      return true
    }
  })
</script>
	
    <script lang="ts">
  import { createTagsInput, type Tag } from '@melt-ui/svelte'
 
  const tagsInput = createTagsInput({
    tags: ['one', 'two'],
    remove: async (t: Tag) => {
      if (t.value === 'one') return false
      return true
    }
  })
</script>
	

API Reference

createTags

The builder function used to create the tags input component.

Props

Prop Default Type / Description
disabled false
boolean

Whether or not the tags input is disabled.

placeholder -
string

The placeholder text for the input element.

editable true
boolean

Whether or not the input is editable.

selected -

The selected tag.

unique false
boolean

Whether or not the tags input should only allow unique tags.

trim true
boolean

Whether or not whitespace from both ends of input string should be removed when a tag is added.

blur true
boolean

Whether or not the input should blur when a tag is added.

addOnPaste false
boolean

Whether or not the input should add tags on paste.

maxTags Infinity
number

The maximum number of tags allowed.

allowed []
string[]

The allowed tags.

denied []
string[]

The disallowed tags.

add -
(tag: string) => Promise<Tag | string>

A function that adds a tag.

remove -
(tag: Tag) => Promise<boolean>

A function that removes a tag.

update -
(tag: Tag) => Promise<Tag>

A function that updates a tag.

defaultTags -
string[] | Tag[]

The default tags to populate the tags input with.

tags -
Writable<Tag[]>

A writable store that controls the tags.

See Bring Your Own Store

onTagsChange -
ChangeFn<Tags[]>

A function that is called when the tags change.

See Change Functions

Elements

Element Description

The builder store used to create the tags input root.

The builder store used to create the tags input input.

The builder store used to create the tags input tag.

The builder store used to create the tags input delete trigger.

The builder store used to create the tags input edit.

States

State Description
tags

A derived store that returns the tags.

inputValue

A derived store that returns the value of the input element.

inputInvalid

A derived store that returns whether or not the input element is invalid.

selected

A derived store that returns the selected tag.

Helpers

Helper Description
isSelected

A derived store that returns a function that checks if a tag is selected.

isInputValid

A method that returns if a input would be valid according to the props defined in the builder.

addTag

A method that attempts to add a tag, the same as if a user tried to.

updateTag

A method that attempts to update a tag, the same as if a user tried to.

removeTag

A method that attempts to remove a tag, the same as if a user tried to.

Options

Option Description
disabled

Whether or not the tags input is disabled.

placeholder

The placeholder text for the input element.

editable

Whether or not the input is editable.

selected

The selected tag.

unique

Whether or not the tags input should only allow unique tags.

trim

Whether or not whitespace from both ends of input string should be removed when a tag is added.

blur

Whether or not the input should blur when a tag is added.

addOnPaste

Whether or not the input should add tags on paste.

maxTags

The maximum number of tags allowed.

allowed

The allowed tags.

denied

The disallowed tags.

add

A function that adds a tag.

remove

A function that removes a tag.

update

A function that updates a tag.

root

The root tags input component.

Data Attributes

Data Attribute Value
[data-disabled]

Present when the tags input is disabled.

[data-focus]

Present if the tags input is focused.

[data-invalid]

Present if the tags input is invalid.

[data-invalid-edit]

Present if the tags input is invalid while editing a tag.

[data-melt-tags-input]

Present on all tags input elements.

Custom Events

Event Value
m-mousedown (e: ) => void

tag

The tag components.

Props

Prop Default Type / Description
id * -
string

A unique ID for the tag

value * -
string

The tag's value

disabled false
boolean

Whether or not the tag is disabled.

Data Attributes

Data Attribute Value
[data-tag-id]

The unique ID of the tag

[data-tag-value]

The value of the tag

[data-disabled]

Present when the tag is disabled.

[data-editing]

Present if the tag is being edited.

[data-selected]

Present when the tag is selected.

[data-melt-tags-input-tag]

Present on all tag elements.

Custom Events

Event Value
m-mousedown (e: ) => void
m-click (e: ) => void
m-dblclick (e: ) => void

deleteTrigger

The button component used to delete a tag.

Props

Prop Default Type / Description
id * -
string

The tag ID the delete trigger will delete.

value * -
string

The tag value the delete trigger will delete.

disabled false
boolean

Whether or not the delete trigger is disabled.

Data Attributes

Data Attribute Value
[data-tag-id]

The unique ID of the tag associated with the delete trigger

[data-tag-value]

The value of the tag associated with the delete trigger.

[data-disabled]

Present when the delete trigger is disabled.

[data-selected]

Present when the delete trigger is selected.

[data-editing]

Present if the tag is being edited.

[data-melt-tags-input-delete-trigger]

Present on all delete trigger elements.

Custom Events

Event Value
m-click (e: ) => void
m-keydown (e: ) => void

edit

The button component used to edit a tag.

Props

Prop Default Type / Description
id * -
string

The tag ID the edit trigger will edit.

value * -
string

The tag value the edit trigger will edit.

Data Attributes

Data Attribute Value
[data-tag-id]

The unique ID of the tag associated with the edit component

[data-tag-value]

The value of the tag associated with the edit component.

[data-melt-tags-input-edit]

Present on all edit elements.

Custom Events

Event Value
m-blur (e: ) => void
m-keydown (e: ) => void
m-input (e: ) => void

input

The hidden input element used for form submission.

Data Attributes

Data Attribute Value
[data-disabled]

Present when the input is disabled.

[data-focus]

Present if the input is focused.

[data-invalid]

Present if the input is invalid.

[data-melt-tags-input-input]

Present on all input elements.

Custom Events

Event Value
m-focus (e: ) => void
m-blur (e: ) => void
m-paste (e: ) => void
m-keydown (e: ) => void
m-input (e: ) => void

Accessibility

Key Behavior
Enter

When focused on the input, adds the tag. When focused on a tag, the tag becomes editable. Pressing enter again saves the tag.

Delete

When focused on a tag, deletes it and moves focus to the right.

Backspace

When focused on an empty input, focuses on the last tag. When focused on a tag, deletes it and moves focus to the left-side tag. If there are no tags to the left, either the next tags gets focus, or the input.

ArrowRight

Moves focus to the next element, be it a tag or input.

ArrowLeft

Moves focus to the previous tag.