Tags
Freeform tag input with inline editing. Arrow/backspace moves the caret so you can insert at any position, click a tag to edit it in place, and control rendering/validation via snippets. Arrow keys do not reorder tags; they only move the caret so tags stay put unless you edit their text.
Press to create a tag at the caret. at the start of a tag pulls the previous tag into edit mode; clicking a pill does the same. and move the cursor around
Usage
<script lang="ts">
import { Tags } from '@obelus/trioxide';
type Tag = { value: string };
let tags: Tag[] = $state([{ value: 'svelte' }]);
const normalize = ({ value }: Tag) => {
const v = value.trim().toLowerCase();
if (!v) return;
return { value: v } satisfies Tag;
};
const shouldCreate: (event: KeyboardEvent) => boolean = (event) =>
event.key === 'Enter' || event.key === ',';
</script>
<Tags
bind:tags
onTag={normalize}
createOn={shouldCreate}
class="flex flex-wrap items-center gap-2 rounded-sm border border-(--trioxide_neutral-7) p-2 focus-within:border-(--trioxide_highlight-10)"
>
{#snippet Tag(tag, props)}
<span class="rounded-sm bg-(--trioxide_neutral-3) px-2 py-1" {...props}>
{tag.value}
<button aria-label={`Remove ${tag.value}`} onclick={() => tags.splice(tags.indexOf(tag), 1)}>
<i class="ri-close-line"></i>
</button>
</span>
{/snippet}
{#snippet PlaceHolder()}
<span class="text-(--trioxide_neutral-7)">Add a tag...</span>
{/snippet}
</Tags> Props
tags/bind:tags: array mutated in place as the user types or deletes; keep it in$stateif you need reactivity.tagsis generic, so each item can carry additional props (id,color,count) that you render insideTag.Tag: snippet(tag, props); render your pill and spreadpropsso the component can handle focus and click-to-edit behavior.PlaceHolder: optional snippet shown when no tags are present and the input is unfocused.createOn(default[' ', 'Enter']): keys that create a tag, or a predicate(event: KeyboardEvent) => booleanto decide per keystroke.onTag({ value }): optional sanitizer; return the normalized tag object to accept it orundefinedto reject (used on creation, blur, and when moving tags around).cursorPropsare used to pass props to the cursor<input>- Remaining
HTMLLabelAttributesapply to the outer<label>(e.g., classes,aria-*).