Mention Input
more-shadcn-noair/mention-inputFreeComponent
An input or textarea that opens a filterable list when you type a trigger character.
Live preview
live · rendered by the registry
Rendered by more-shadcn-noair on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://more-shadcn.noair.fun/r/mention-input.jsonSource
1<script lang="ts" module>2 export type MentionItem = {3 id: string;4 label: string;5 description?: string;6 keywords?: string[];7 [key: string]: unknown;8 };9</script>1011<script lang="ts">12 import { cn } from '$UTILS$';13 import { tick } from 'svelte';14 import { fly } from 'svelte/transition';15 import type { Snippet } from 'svelte';1617 let {18 value = $bindable(''),19 items = [],20 trigger = '@',21 placeholder = 'Type @ to mention someone...',22 disabled = false,23 multiline = true,24 rows = 4,25 maxItems = 8,26 insertSpace = true,27 class: className,28 filter,29 onmention,30 itemSnippet,31 emptySnippet,32 ...rest33 }: {34 value?: string;35 items?: MentionItem[];36 trigger?: string;37 placeholder?: string;38 disabled?: boolean;39 /** Render a `<textarea>`; set to false for a single-line `<input>`. */40 multiline?: boolean;41 rows?: number;42 maxItems?: number;43 insertSpace?: boolean;44 class?: string;45 filter?: (items: MentionItem[], query: string) => MentionItem[];46 onmention?: (item: MentionItem) => void;47 itemSnippet?: Snippet<[MentionItem, boolean]>;48 emptySnippet?: Snippet<[string]>;49 [key: string]: unknown;50 } = $props();5152 type Field = HTMLTextAreaElement | HTMLInputElement;5354 let fieldRef = $state<Field | null>(null);55 let listRef = $state<HTMLDivElement | null>(null);5657 const uid = $props.id();58 const listId = `mention-input-list-${uid}`;5960 let isOpen = $state(false);61 let query = $state('');62 let activeIndex = $state(0);63 /** Index of the trigger character in `value`. */64 let anchorIndex = $state(-1);65 let caret = $state({ top: 0, left: 0, height: 20 });6667 const defaultFilter = (list: MentionItem[], q: string) => {68 if (!q) return list;69 const needle = q.toLowerCase();70 return list.filter((item) => {71 if (item.label.toLowerCase().includes(needle)) return true;72 if (item.description?.toLowerCase().includes(needle)) return true;73 return item.keywords?.some((k) => k.toLowerCase().includes(needle)) ?? false;74 });75 };7677 const results = $derived.by(() => {78 const filtered = (filter ?? defaultFilter)(items, query);79 return maxItems > 0 ? filtered.slice(0, maxItems) : filtered;80 });8182 function close() {83 isOpen = false;84 anchorIndex = -1;85 query = '';86 activeIndex = 0;87 }8889 /**90 * Mirrors the field into a hidden div to find the pixel offset of the caret,91 * so the popover can be anchored to the trigger character instead of the field.92 */93// … truncated
More from more-shadcn-noair
All 43 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Audioaudio | more-shadcn-noair | Components | Free | no deps | |
| Audio Waveaudio-wave | more-shadcn-noair | Components | Free | no deps | |
| Autocompleteautocomplete | more-shadcn-noair | Components | Free | no deps | |
| Bannerbanner | more-shadcn-noair | Components | Free | no deps | |
| Big Calendarbig-calendar | more-shadcn-noair | Components | Free | no deps | |
| Bottom Navigationbottom-nav | more-shadcn-noair | Components | Free | no deps | |
| Canvascanvas | more-shadcn-noair | Components | Free | no deps | |
| Chipchip | more-shadcn-noair | Components | Free | no deps |
