Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelogApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UIARC Radiant Components
v4.9DocsComponentsTokensSynthesizer
Getting StartedFrameworksServer RenderingDesign TokensThemingTheme SynthesizerTypographyUtilitiesAll ComponentsAccessibilityBrowser SupportChangelogContributingStatsApp ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbarAnchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree ViewAccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual ListActivity HeatmapAnimated NumberBadgeBar ListChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveformBlockquoteCode BlockCode GroupGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriterButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerField ListFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree SelectAlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Tag Input

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

ComponentsTag Input
inputinteractivebeta
<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, which makes importing comma-separated lists fast. 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, and 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>

API

delimiterstring','
Character that commits the current text as a tag when typed; pasted text is split on it.
labelstring''
Visible label rendered above the field in a small uppercase style.
placeholderstring''
Hint text shown inside the field when no tags exist and the input is empty.
namestring''
Form field name. Each tag is submitted as its own FormData entry under this name.
disabledbooleanfalse
Disables the control, preventing interaction and reducing opacity to 50%.
errorstring''
Error message shown below the field; also applies error styling to the border.
valuestring[][]
Array of current tags. Updated on add/remove and emitted via arc-change.
suggestionsstring[][]
Autocomplete candidates. When non-empty, typing filters them into a dropdown listbox.
maxTagsnumber0
Maximum number of tags (0 = unlimited). At the limit, entry is disabled with a "-- max reached" hint.
allowCustombooleantrue
When false, only values from suggestions can be added; free text is rejected.
readonlybooleanfalse
Prevents adding or removing tags while the field stays focusable and the tags still submit with the form.
size'sm' | 'md' | 'lg''md'
Control size. md is the default; sm and lg scale the field height and padding.
formAssociatedbooleantrue
propertiesobject{ // flag(), unlike `disabled`. The exclusion in props.js is specifically // about form-associated *platform* semantics: a `disabled` content // attribute that is merely present makes the element actually disabled // per the HTML spec, and formDisabledCallback assigns the property back, // so no converter can win. Neither of these is platform-mapped: // `required` is enforced by _computeValidity() below and `readonly` by // each component's own interaction handlers, so the stock converter buys // nothing here and costs the usual bug: `required="false"` read as true, // blocking submission of a form the author meant to leave optional. // Finding #48's shape, across all 26 form controls at once. required: flag(false), readonly: flag(false), }
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).
autoValidatesbooleantrue
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
requiredbooleanfalse

Methods

checkValidity()boolean
Whether the control currently satisfies its constraints, per the native constraint-validation API. Fires invalid on the element when it does not, and reports nothing to the user.
reportValidity()boolean
As checkValidity(), but also shows the browser's validation message against the control when it fails.

Events

arc-changedetail:{ 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