UIPackage

Tags Input

Vue form
Edit on GitHub

Multi-tag input — type a value, hit Enter, get a Chip. Backspace removes the last tag. Use for email recipient lists, tag sets, and free-form keyword inputs.

Also available for React ->

Installation

$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/tags-input.json

Or with the named registry: npx shadcn-vue@latest add @uipkge/tags-input

Examples

Props

Name Type / Values Default Required
class HTMLAttributes['class'] optional

Dependencies

Files (6)

  • app/components/ui/tags-input/TagsInput.vue 1.1 kB
    <script setup lang="ts">
    import type { TagsInputRootEmits, TagsInputRootProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    import { reactiveOmit } from '@vueuse/core'
    import { TagsInputRoot, useForwardPropsEmits } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<TagsInputRootProps & { class?: HTMLAttributes['class'] }>()
    const emits = defineEmits<TagsInputRootEmits>()
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwarded = useForwardPropsEmits(delegatedProps, emits)
    </script>
    
    <template>
      <TagsInputRoot
        v-slot="slotProps"
        v-bind="forwarded"
        :class="
          cn(
            'border-input bg-background flex flex-wrap items-center gap-2 rounded-md border px-2 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none',
            'focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]',
            'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
            props.class,
          )
        "
      >
        <slot v-bind="slotProps" />
      </TagsInputRoot>
    </template>
  • app/components/ui/tags-input/TagsInputInput.vue 0.6 kB
    <script setup lang="ts">
    import type { TagsInputInputProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    import { reactiveOmit } from '@vueuse/core'
    import { TagsInputInput, useForwardProps } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<TagsInputInputProps & { class?: HTMLAttributes['class'] }>()
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwardedProps = useForwardProps(delegatedProps)
    </script>
    
    <template>
      <TagsInputInput
        v-bind="forwardedProps"
        :class="cn('min-h-5 flex-1 bg-transparent px-1 text-sm focus:outline-none', props.class)"
      />
    </template>
  • app/components/ui/tags-input/TagsInputItem.vue 0.8 kB
    <script setup lang="ts">
    import type { TagsInputItemProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    
    import { reactiveOmit } from '@vueuse/core'
    import { TagsInputItem, useForwardProps } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<TagsInputItemProps & { class?: HTMLAttributes['class'] }>()
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwardedProps = useForwardProps(delegatedProps)
    </script>
    
    <template>
      <TagsInputItem
        v-bind="forwardedProps"
        :class="
          cn(
            'bg-secondary data-[state=active]:ring-ring ring-offset-background flex h-5 items-center rounded-md data-[state=active]:ring-2 data-[state=active]:ring-offset-2',
            props.class,
          )
        "
      >
        <slot />
      </TagsInputItem>
    </template>
  • app/components/ui/tags-input/TagsInputItemDelete.vue 0.7 kB
    <script setup lang="ts">
    import type { TagsInputItemDeleteProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    import { reactiveOmit } from '@vueuse/core'
    import { X } from 'lucide-vue-next'
    import { TagsInputItemDelete, useForwardProps } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<TagsInputItemDeleteProps & { class?: HTMLAttributes['class'] }>()
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwardedProps = useForwardProps(delegatedProps)
    </script>
    
    <template>
      <TagsInputItemDelete v-bind="forwardedProps" :class="cn('mr-1 flex rounded bg-transparent', props.class)">
        <slot>
          <X class="h-4 w-4" aria-hidden="true" />
        </slot>
      </TagsInputItemDelete>
    </template>
  • app/components/ui/tags-input/TagsInputItemText.vue 0.6 kB
    <script setup lang="ts">
    import type { TagsInputItemTextProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    import { reactiveOmit } from '@vueuse/core'
    import { TagsInputItemText, useForwardProps } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<TagsInputItemTextProps & { class?: HTMLAttributes['class'] }>()
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwardedProps = useForwardProps(delegatedProps)
    </script>
    
    <template>
      <TagsInputItemText v-bind="forwardedProps" :class="cn('rounded bg-transparent px-2 py-0.5 text-sm', props.class)">
        <slot />
      </TagsInputItemText>
    </template>
  • app/components/ui/tags-input/index.ts 0.3 kB
    export { default as TagsInput } from './TagsInput.vue'
    export { default as TagsInputInput } from './TagsInputInput.vue'
    export { default as TagsInputItem } from './TagsInputItem.vue'
    export { default as TagsInputItemDelete } from './TagsInputItemDelete.vue'
    export { default as TagsInputItemText } from './TagsInputItemText.vue'

Raw manifest: https://uipkge.dev/r/vue/tags-input.json