Introduction
Multi-trigger inline mentions for React, Vue, Svelte, and Angular. Built on a framework-agnostic core.
What is @skyastrall/mentions?
A production-grade mentions input that supports @users, #tags, /commands, and custom triggers — each with its own data source, color, and configuration.
It ships as a core engine and thin framework adapters:
@skyastrall/mentions-core— Framework-agnostic state machine, markup parser, trigger detection. ~6KB gzipped.@skyastrall/mentions-react— React adapter with drop-in component, compound components, and headless hook. ~4KB.@skyastrall/mentions-vue— Vue 3 adapter with composable and compound components. ~4KB.@skyastrall/mentions-svelte— Svelte 5 adapter with composable and compound components. ~5KB.@skyastrall/mentions-angular— Angular adapter with standalone component, signals, andControlValueAccessor. ~5KB.
Three API Layers
Pick the level of control you need:
1. Drop-in Component
One import, one component, works out of the box.
<Mentions
triggers={[{ char: "@", data: users }]}
onChange={(markup, plainText) => {}}
/> <Mentions
:triggers="[{ char: '@', data: users }]"
v-model="markup"
/> <Mentions
triggers={[{ char: "@", data: users }]}
onChange={(markup, plainText) => {}}
/> <sa-mentions
[triggers]="[{ char: '@', data: users }]"
[(ngModel)]="markup"
/> 2. Compound Components
Control the layout. The library handles state, ARIA, and keyboard navigation. (Angular is component-first — it ships a single <sa-mentions>; for custom layout drop to the headless bridge below.)
<Mentions triggers={triggers}>
<Mentions.Editor placeholder="Type @..." />
<Mentions.Portal>
<Mentions.List>
<Mentions.Item render={({ item }) => <UserCard user={item} />} />
</Mentions.List>
</Mentions.Portal>
</Mentions> <Mentions :triggers="triggers">
<MentionsEditor placeholder="Type @..." />
<MentionsPortal>
<MentionsList>
<MentionsItem v-slot="{ item }">
<UserCard :user="item" />
</MentionsItem>
</MentionsList>
</MentionsPortal>
</Mentions> <Mentions {triggers}>
<MentionsEditor placeholder="Type @..." />
<MentionsPortal>
<MentionsList>
<MentionsItem>
{#snippet children({ item })}
<UserCard user={item} />
{/snippet}
</MentionsItem>
</MentionsList>
</MentionsPortal>
</Mentions> <!-- Angular renders a complete component; configure it via inputs -->
<sa-mentions
[triggers]="triggers"
[(ngModel)]="markup"
placeholder="Type @..."
/>
<!-- For full layout control, drive the headless bridge yourself (below). --> 3. Headless Hook / Composable
Full control. You get props, state, and helpers — render whatever you want.
const { inputProps, listProps, getItemProps, editorRef, isOpen, items } =
useMentions({ triggers }); const { aria, editorRef, isOpen, items, handleInput, handleKeyDown } =
useMentions({ triggers }); const api = useMentions({ triggers });
// api.isOpen, api.items, api.aria, api.handleInput, ... import { DestroyRef, inject } from "@angular/core";
import { MentionsControllerBridge } from "@skyastrall/mentions-angular";
// state() is a signal; drive everything through the controller.
bridge = new MentionsControllerBridge({ triggers }, inject(DestroyRef));
// bridge.state().items, .status, .query ...
// bridge.controller.handleInputChange(markup, plainText, cursor); Key Features
- Multi-trigger support with per-trigger colors and data sources
- Framework-agnostic core — React, Vue, Svelte, and Angular adapters shipped
- Contenteditable with DOM-first architecture
- Ghost text for AI inline completions (Tab to accept)
- Async data with debounce, abort, and loading states
- Single-line mode with Enter/paste/drop prevention
- WAI-ARIA combobox pattern with keyboard navigation
- ~6KB core + ~4–5KB adapter gzipped, zero runtime dependencies in core