@app-studio/components
TagInput
A form input component for managing a list of tags. Users can add tags by typing and pressing Enter or comma, and remove them by clicking the X button or using backspace.
View component sourceImport
ts
import { TagInput } from '@app-studio/components';New to the library? Complete installation and provider setup first.
Interactive examples
Try the component, then open Code to copy the complete example.
import React, { useState } from 'react';
import { Vertical, Text } from 'app-studio';
import { TagInput } from '@app-studio/components';
/**
* Default TagInput example
*/
export const DefaultTagInput = () => {
const [tags, setTags] = useState<string[]>([]);
return (
<Vertical gap={20}>
<Text>Default Tag Input:</Text>
<TagInput
// name="tags"
label="Tags"
placeholder="Type tags and press Enter..."
tags={tags}
onTagsChange={setTags}
helperText="Add relevant tags for your content"
/>
<Text fontSize={14} color="color-gray-600">
Current tags: {Array.isArray(tags) ? tags.join(', ') : 'None'}
</Text>
</Vertical>
);
};
/**
* TagInput with custom separators
*/
export const CustomSeparatorsTagInput = () => {
const [tags, setTags] = useState<string[]>(['react', 'typescript']);
return (
<Vertical gap={20}>
<Text>Custom Separators (Enter, Comma, Space):</Text>
<TagInput
name="customTags"
label="Skills"
placeholder="Use Enter, comma, or space to add skills..."
tags={tags}
onTagsChange={setTags}
separators={['enter', 'comma', 'space']}
variant="outline"
shape="rounded"
size="lg"
/>
</Vertical>
);
};
/**
* TagInput with maximum limit
*/
export const LimitedTagInput = () => {
const [tags, setTags] = useState<string[]>(['javascript', 'web']);
return (
<Vertical gap={20}>
<Text>Limited to 5 tags:</Text>
<TagInput
name="limitedTags"
label="Technologies"
placeholder="Add up to 5 technologies..."
tags={tags}
onTagsChange={setTags}
maxTags={5}
variant="outline"
helperText={`${tags.length}/5 tags used`}
/>
</Vertical>
);
};
/**
* TagInput with validation
*/
export const ValidatedTagInput = () => {
const [tags, setTags] = useState<string[]>([]);
return (
<Vertical gap={20}>
<Text>With Validation (3-20 chars, no duplicates):</Text>
<TagInput
name="validatedTags"
label="Categories"
placeholder="Add categories..."
tags={tags}
onTagsChange={setTags}
minTagLength={3}
maxTagLength={20}
allowDuplicates={false}
variant="outline"
shape="pill"
helperText="Tags must be 3-20 characters long"
/>
</Vertical>
);
};
/**
* Disabled and ReadOnly states
*/
export const DisabledTagInput = () => {
return (
<Vertical gap={20}>
<Text>Disabled State:</Text>
<TagInput
name="disabledTags"
label="Disabled Tags"
tags={['disabled', 'example']}
isDisabled={true}
helperText="This input is disabled"
/>
<Text>Read-Only State:</Text>
<TagInput
name="readonlyTags"
label="Read-Only Tags"
tags={['readonly', 'example']}
isReadOnly={true}
isRemovable={false}
helperText="This input is read-only"
/>
</Vertical>
);
};
/**
* Custom styled TagInput
*/
export const StyledTagInput = () => {
const [tags, setTags] = useState<string[]>(['design', 'ui']);
return (
<Vertical gap={20}>
<Text>Custom Styled:</Text>
<TagInput
name="styledTags"
label="Design Tags"
placeholder="Add design-related tags..."
tags={tags}
onTagsChange={setTags}
variant="none"
shape="rounded"
shadow={{ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 12px' }}
views={{
inputContainer: {
borderColor: 'theme-primary',
borderWidth: '2px',
backgroundColor: 'color-blue-50',
},
tag: {
backgroundColor: 'theme-primary',
borderColor: 'theme-primary',
},
tagText: {
color: 'color-white',
},
tagRemove: {
_hover: {
backgroundColor: 'rgba(255, 255, 255, 0.2)',
},
},
label: {
color: 'theme-primary',
fontWeight: 'bold',
},
}}
/>
</Vertical>
);
};Props
Required props are marked below. A dash indicates an unspecified default. Design system configuration can override implementation defaults.
Scroll horizontally to see every column.
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | See the type and source declaration for this property.Source |
name | string | — | Field name used by forms and Formik bindings.Source |
label | string | — | Visible label rendered alongside the input. Form-library wrappers (Switch, TextField, Checkbox, …) consume this. Not a native HTML attribute on <input>, but conventionally part of the form-control prop surface.Source |
helperText | string | — | Helper text rendered below the input (hint / error / explanation).Source |
error | string | boolean | false | Error state — usually a string for the error message, or a boolean toggle.Source |
placeholder | string | 'Type and press Enter to add tags...' | Hint displayed while the field is empty.Source |
tags | string[] | [] | See the type and source declaration for this property.Source |
defaultTags | string[] | — | See the type and source declaration for this property.Source |
onTagsChange | ((tags: string[]) => void) | — | See the type and source declaration for this property.Source |
onTagAdd | ((tag: string) => void) | — | See the type and source declaration for this property.Source |
onTagRemove | ((tag: string, index: number) => void) | — | See the type and source declaration for this property.Source |
maxTags | number | — | See the type and source declaration for this property.Source |
minTagLength | number | — | See the type and source declaration for this property.Source |
maxTagLength | number | — | See the type and source declaration for this property.Source |
allowDuplicates | boolean | — | See the type and source declaration for this property.Source |
separators | TagSeparator[] | — | See the type and source declaration for this property.Source |
isDisabled | boolean | false | Disables user interaction.Source |
isReadOnly | boolean | false | Keeps the value visible without allowing edits.Source |
isAutoFocus | boolean | false | See the type and source declaration for this property.Source |
isRemovable | boolean | true | See the type and source declaration for this property.Source |
size | Size"sm""md""lg""xs""xl" | 'md' | Size preset for the component.Source |
shape | Shape"square""rounded""pill""default" | 'default' | Shape preset for the component.Source |
variant | Variant"outline""default""none" | 'default' | Visual treatment of the component.Source |
shadow | ViewProps | Shadow | Elevation | {} | Shadow or elevation styling.Source |
views | TagInputStyles | {} | Style overrides for the named internal parts.Source |
left | View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | — | See the type and source declaration for this property.Source |
right | View typestring | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | — | See the type and source declaration for this property.Source |
onFocus | (() => void) | — | See the type and source declaration for this property.Source |
onBlur | (() => void) | — | See the type and source declaration for this property.Source |
onClick | (() => void) | — | Called when the user activates the component.Source |
menuItems | string[] | — | See the type and source declaration for this property.Source |
onMenuItemSelect | ((item: string) => void) | — | See the type and source declaration for this property.Source |
Common inherited styling props (6)
Scroll horizontally to see every column.
| Prop | Type | Default | Description |
|---|---|---|---|
media | Record<string, CssProps> | — | See the type and source declaration for this property. |
as | keyof JSX.IntrinsicElements"symbol""object""slot""style""title""pattern""form""animate""clipPath""filter""marker""mask""a""abbr""address""area""article""aside""audio""b""base""bdi""bdo""big""blockquote""body""br""button""canvas""caption""center""cite""code""col""colgroup""data""datalist""dd""del""details""dfn""dialog""div""dl""dt""em""embed""fieldset""figcaption""figure""footer""h1""h2""h3""h4""h5""h6""head""header""hgroup""hr""html""i""iframe""img""input""ins""kbd""keygen""label""legend""li""link""main""map""mark""menu""menuitem""meta""meter""nav""noindex""noscript""ol""optgroup""option""output""p""param""picture""pre""progress""q""rp""rt""ruby""s""samp""search""script""section""select""small""source""span""strong""sub""summary""sup""table""template""tbody""td""textarea""tfoot""th""thead""time""tr""track""u""ul""var""video""wbr""webview""svg""animateMotion""animateTransform""circle""defs""desc""ellipse""feBlend""feColorMatrix""feComponentTransfer""feComposite""feConvolveMatrix""feDiffuseLighting""feDisplacementMap""feDistantLight""feDropShadow""feFlood""feFuncA""feFuncB""feFuncG""feFuncR""feGaussianBlur""feImage""feMerge""feMergeNode""feMorphology""feOffset""fePointLight""feSpecularLighting""feSpotLight""feTile""feTurbulence""foreignObject""g""image""line""linearGradient""metadata""mpath""path""polygon""polyline""radialGradient""rect""set""stop""switch""text""textPath""tspan""use""view" | — | See the type and source declaration for this property. |
themeMode | "light" | "dark""light""dark" | — | See the type and source declaration for this property. |
_hover | string | CssProps | — | See the type and source declaration for this property. |
_active | string | CssProps | — | See the type and source declaration for this property. |
_focus | string | CssProps | — | See the type and source declaration for this property. |
For shared layout, color, and responsive properties, read Styling & composition and Responsive layouts. Additional native element attributes depend on the target platform.
Usage guidance
- Give controls a visible label or an accessible name, and verify keyboard interaction. See Accessibility.
- For controlled inputs, update the value from the callback shown in the props table. Keep application state in your component or form library.
- These previews run in the browser. Check React Native setup for platform requirements and differences.