Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
ARC UI ARC Radiant Components
v3.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip

Tag Input

Free-text token entry field with optional autocomplete suggestions, delimiter splitting, and duplicate rejection.

Components Tag Input
input interactive beta
<arc-tag-input>

Overview

TagInput lets users build a list of free-text values as removable tag chips. Typing a value and pressing Enter — or the configurable delimiter character (comma by default) — commits the trimmed text as a tag. Pasting text containing delimiters splits it into multiple tags at once, making it fast to import comma-separated lists. An optional `suggestions` array turns the field into a lightweight autocomplete: as the user types, matching suggestions appear in a dropdown listbox navigable with ArrowUp/ArrowDown and committed with Enter or a click. Free text is still allowed alongside suggestions unless `allowCustom` is set to false, in which case only values from the suggestion list can be added. Duplicate entries are rejected — the existing chip shakes briefly to show why nothing was added (the animation is suppressed under reduced-motion preferences). TagInput is form-associated: it submits one FormData entry per tag under its `name`, so servers receive the values as a repeated field. A `maxTags` limit disables further entry with a "-- max reached" hint once reached. Keyboard editing mirrors MultiSelect: Backspace in an empty input removes the last tag, and ArrowLeft from the start of the input walks focus into the chips where arrows navigate and Backspace/Delete removes.

Guidelines

When to use

  • Always provide a `label` so the field is accessible to screen readers
  • Provide `suggestions` when a known vocabulary exists — it speeds entry and reduces typos
  • Set `allowCustom` to false when values must come from a controlled vocabulary
  • Use `maxTags` to cap entries when downstream systems limit how many values are accepted
  • Listen to `arc-input` to fetch or refine suggestions from a server as the user types

When not to use

  • Do not use TagInput when values must be chosen from a fixed list and casual browsing matters — use MultiSelect instead
  • Do not pick a delimiter character that legitimately appears inside your values
  • Do not use extremely long tag values — they will overflow the chips
  • Do not rely on the shake animation alone to explain rejected input in critical flows — pair with an `error` message where it matters

Features

  • Free-text tag creation on Enter or a configurable delimiter character (comma by default)
  • Paste splitting: pasted text containing delimiters becomes multiple tags in one action
  • Optional autocomplete dropdown driven by a `suggestions` array with type-ahead filtering
  • `allowCustom={false}` restricts entry to suggestion values only
  • Duplicate rejection with a brief shake animation on the existing chip (respects reduced motion)
  • `maxTags` limit with an inline "-- max reached" hint when full
  • Full keyboard editing: Backspace removes the last tag, ArrowLeft walks into chips, arrows navigate, Backspace/Delete removes, Escape returns to the input
  • Form-associated: submits one FormData entry per tag under `name`

Preview

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<arc-tag-input
  label="Topics"
  placeholder="Add a topic..."
  suggestions='["JavaScript","TypeScript","Python"]'
  max-tags="5"
></arc-tag-input>
import { TagInput } from '@arclux/arc-ui-react';

export default function Example() {
  return (
    <TagInput
      label="Topics"
      placeholder="Add a topic..."
      suggestions={['JavaScript', 'TypeScript', 'Python']}
      maxTags={5}
      onArcChange={(e) => console.log(e.detail.value)}
    />
  );
}
<script setup>
import { TagInput } from '@arclux/arc-ui-vue';
</script>

<template>
  <TagInput
    label="Topics"
    placeholder="Add a topic..."
    :suggestions="['JavaScript', 'TypeScript', 'Python']"
    :maxTags="5"
  />
</template>
<script>
  import { TagInput } from '@arclux/arc-ui-svelte';
</script>

<TagInput
  label="Topics"
  placeholder="Add a topic..."
  suggestions={['JavaScript', 'TypeScript', 'Python']}
  maxTags={5}
/>
import { Component } from '@angular/core';
import { TagInput } from '@arclux/arc-ui-angular';

@Component({
  imports: [TagInput],
  template: `
    <arc-tag-input
      label="Topics"
      placeholder="Add a topic..."
      [suggestions]="['JavaScript', 'TypeScript', 'Python']"
      [maxTags]="5"
    />
  `,
})
export class MyComponent {}
import { TagInput } from '@arclux/arc-ui-solid';

export default function Example() {
  return (
    <TagInput
      label="Topics"
      placeholder="Add a topic..."
      suggestions={['JavaScript', 'TypeScript', 'Python']}
      maxTags={5}
    />
  );
}
import { TagInput } from '@arclux/arc-ui-preact';

export default function Example() {
  return (
    <TagInput
      label="Topics"
      placeholder="Add a topic..."
      suggestions={['JavaScript', 'TypeScript', 'Python']}
      maxTags={5}
    />
  );
}

API

size 'sm' | 'md' | 'lg' 'md'
Control size. `md` is the default; `sm` and `lg` scale the field height and padding.
value string[] []
Array of current tags. Updated on add/remove and emitted via `arc-change`.
suggestions string[] []
Autocomplete candidates. When non-empty, typing filters them into a dropdown listbox.
delimiter string ','
Character that commits the current text as a tag when typed; pasted text is split on it.
max-tags number 0
Maximum number of tags (0 = unlimited). At the limit, entry is disabled with a "-- max reached" hint.
allow-custom boolean true
When false, only values from `suggestions` can be added; free text is rejected.
label string ''
Visible label rendered above the field in a small uppercase style.
placeholder string ''
Hint text shown inside the field when no tags exist and the input is empty.
name string ''
Form field name. Each tag is submitted as its own FormData entry under this name.
disabled boolean false
Disables the control, preventing interaction and reducing opacity to 50%.
error string ''
Error message shown below the field; also applies error styling to the border.
readonly boolean false
Prevents adding or removing tags while the field stays focusable and the tags still submit with the form.
formAssociated boolean true
properties object { required: { type: Boolean, reflect: true }, readonly: { type: Boolean, reflect: true }, }
Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. `required` participates in constraint validation below; `readonly` reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
autoValidates boolean true
Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
form
validity
validationMessage
required boolean false

Events

arc-change detail: { value: string[] }
Fired when a tag is added or removed; detail contains `{ value }`
arc-input
Fired as the user types; detail contains `{ query }`

See Also