Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Twilio-labs/paste/llms.txt
Use this file to discover all available pages before exploring further.
About Form Pill Group
Form Pill Group is an interactive component for managing collections of items that users can select, deselect, and remove. Use it for multi-select interfaces, tag management, or any scenario where users need to manage a list of discrete items.
Components
- FormPillGroup - Container for form pills
- FormPill - Individual interactive pill
- useFormPillState - Hook for managing pill state
Installation
yarn add @twilio-paste/form-pill-group
Usage
import { FormPillGroup, FormPill, useFormPillState } from '@twilio-paste/form-pill-group';
const MyFormPills = () => {
const pillState = useFormPillState();
const [pills, setPills] = React.useState(['Option 1', 'Option 2', 'Option 3']);
const handleRemove = (pillToRemove) => {
setPills(pills.filter(pill => pill !== pillToRemove));
};
return (
<FormPillGroup {...pillState} aria-label="Selected options:">
{pills.map((pill) => (
<FormPill
key={pill}
{...pillState}
onDismiss={() => handleRemove(pill)}
>
{pill}
</FormPill>
))}
</FormPillGroup>
);
};
Props
FormPillGroup
Also accepts state props from useFormPillState.
FormPill
Also accepts state props from useFormPillState.
State Management
Use useFormPillState to manage keyboard navigation and selection:
const pillState = useFormPillState();
<FormPillGroup {...pillState} aria-label="Items:">
<FormPill {...pillState} onDismiss={handleRemove1}>Item 1</FormPill>
<FormPill {...pillState} onDismiss={handleRemove2}>Item 2</FormPill>
</FormPillGroup>
Removable Pills
Pills with onDismiss show a close button:
const [items, setItems] = React.useState(['Tag 1', 'Tag 2', 'Tag 3']);
const pillState = useFormPillState();
const removeItem = (itemToRemove) => {
setItems(items.filter(item => item !== itemToRemove));
};
<FormPillGroup {...pillState} aria-label="Tags:">
{items.map(item => (
<FormPill
key={item}
{...pillState}
onDismiss={() => removeItem(item)}
>
{item}
</FormPill>
))}
</FormPillGroup>
Selectable Pills
Pills can be selected/deselected:
const [selectedPills, setSelectedPills] = React.useState([]);
const pillState = useFormPillState();
const togglePill = (pill) => {
if (selectedPills.includes(pill)) {
setSelectedPills(selectedPills.filter(p => p !== pill));
} else {
setSelectedPills([...selectedPills, pill]);
}
};
<FormPillGroup {...pillState} aria-label="Select options:">
{options.map(option => (
<FormPill
key={option}
{...pillState}
selected={selectedPills.includes(option)}
onClick={() => togglePill(option)}
>
{option}
</FormPill>
))}
</FormPillGroup>
Size Variants
Default Size
<FormPillGroup {...pillState} aria-label="Items:" size="default">
<FormPill {...pillState}>Item</FormPill>
</FormPillGroup>
Large Size
<FormPillGroup {...pillState} aria-label="Items:" size="large">
<FormPill {...pillState}>Item</FormPill>
</FormPillGroup>
Variant Types
Listbox Variant (default)
Standard selectable pills:
<FormPillGroup {...pillState} aria-label="Items:" variant="listbox">
{/* pills */}
</FormPillGroup>
Tree Variant
Allows pills to trigger other elements like dialogs:
<FormPillGroup {...pillState} aria-label="Items:" variant="tree">
<FormPill {...pillState} onClick={openDialog}>Configure</FormPill>
</FormPillGroup>
With Icons
Add icons to pills:
import { UserIcon } from '@twilio-paste/icons/esm';
<FormPillGroup {...pillState} aria-label="Users:">
<FormPill {...pillState}>
<UserIcon decorative size="sizeIcon10" />
John Doe
</FormPill>
</FormPillGroup>
Keyboard Navigation
Form Pill Group supports keyboard interaction:
- Arrow keys - Navigate between pills
- Enter - Toggle pill selection
- Delete/Backspace - Remove focused pill (if dismissible)
- Tab - Move focus in/out of group
Accessibility
- Uses
role="listbox" or role="tree" for proper semantics
- Each pill has
role="option" or role="treeitem"
- Keyboard navigation fully supported
- Selected state announced to screen readers
- Keyboard controls visually hidden but available to assistive tech
- Requires
aria-label for context
Common Use Cases
Tag Management
const [tags, setTags] = React.useState(['React', 'TypeScript']);
<FormPillGroup {...pillState} aria-label="Tags:">
{tags.map(tag => (
<FormPill
key={tag}
{...pillState}
onDismiss={() => setTags(tags.filter(t => t !== tag))}
>
{tag}
</FormPill>
))}
</FormPillGroup>
Multi-Select Filter
const [filters, setFilters] = React.useState(['Active', 'Premium']);
<FormPillGroup {...pillState} aria-label="Active filters:">
{filters.map(filter => (
<FormPill
key={filter}
{...pillState}
selected
onDismiss={() => removeFilter(filter)}
>
{filter}
</FormPill>
))}
</FormPillGroup>
Recipient List
const [recipients, setRecipients] = React.useState(['user1@example.com']);
<FormPillGroup {...pillState} aria-label="Recipients:">
{recipients.map(email => (
<FormPill
key={email}
{...pillState}
onDismiss={() => removeRecipient(email)}
>
{email}
</FormPill>
))}
</FormPillGroup>
Best Practices
- Provide clear
aria-label for the group
- Use for managing collections of items
- Allow removal of items when appropriate
- Limit visible pills (consider scrolling or “show more”)
Don’t
- Don’t use for read-only data (use Display Pill Group)
- Don’t show too many pills at once
- Don’t forget keyboard controls
- Don’t use for single selection (use Radio Group)
Related components