Quick Start

Get a working mentions input in under a minute.

Basic Usage

Import Mentions, define your data, render the component.

import { Mentions } from "@skyastrall/mentions-react";

const users = [
  { id: "1", label: "Alice Johnson" },
  { id: "2", label: "Bob Smith" },
  { id: "3", label: "Charlie Brown" },
];

function App() {
  return (
    <Mentions
      triggers={[{ char: "@", data: users }]}
      placeholder="Type @ to mention someone..."
      onChange={(markup, plainText) => {
        console.log("Markup:", markup);
        console.log("Plain:", plainText);
      }}
    />
  );
}
<script setup>
import { ref } from "vue";
import { Mentions } from "@skyastrall/mentions-vue";

const users = [
  { id: "1", label: "Alice Johnson" },
  { id: "2", label: "Bob Smith" },
  { id: "3", label: "Charlie Brown" },
];

const markup = ref("");
</script>

<template>
  <Mentions
    :triggers="[{ char: '@', data: users }]"
    placeholder="Type @ to mention someone..."
    v-model="markup"
  />
</template>
<script>
import { Mentions } from "@skyastrall/mentions-svelte";

const users = [
  { id: "1", label: "Alice Johnson" },
  { id: "2", label: "Bob Smith" },
  { id: "3", label: "Charlie Brown" },
];

let markup = $state("");
</script>

<Mentions
  triggers={[{ char: "@", data: users }]}
  placeholder="Type @ to mention someone..."
  onChange={(m, plainText) => {
    markup = m;
    console.log("Markup:", m);
    console.log("Plain:", plainText);
  }}
/>

Type @ in the editor. A dropdown appears. Select a user — it becomes a highlighted mention.

Multiple Triggers

<Mentions
  triggers={[
    { char: "@", data: users, color: "oklch(0.75 0.15 250)" },
    { char: "#", data: tags, color: "oklch(0.75 0.12 300)" },
    { char: "/", data: commands, color: "oklch(0.80 0.12 80)" },
  ]}
  onChange={(markup, plainText) => {}}
/>
<Mentions
  :triggers="[
    { char: '@', data: users, color: 'oklch(0.75 0.15 250)' },
    { char: '#', data: tags, color: 'oklch(0.75 0.12 300)' },
    { char: '/', data: commands, color: 'oklch(0.80 0.12 80)' },
  ]"
  v-model="markup"
/>
<Mentions
  triggers={[
    { char: "@", data: users, color: "oklch(0.75 0.15 250)" },
    { char: "#", data: tags, color: "oklch(0.75 0.12 300)" },
    { char: "/", data: commands, color: "oklch(0.80 0.12 80)" },
  ]}
  onChange={(m, p) => { markup = m; }}
/>

Understanding the Markup

The component emits two values on change:

Store the markup. Display the plain text. Parse mentions when needed:

import { extractMentions } from "@skyastrall/mentions-react";

const mentions = extractMentions(markup, triggers);
// [{ id: "1", label: "Alice Johnson" }, { id: "t1", label: "urgent" }]
import { extractMentions } from "@skyastrall/mentions-vue";

const mentions = extractMentions(markup.value, triggers);
// [{ id: "1", label: "Alice Johnson" }, { id: "t1", label: "urgent" }]
import { extractMentions } from "@skyastrall/mentions-svelte";

const mentions = extractMentions(markup, triggers);
// [{ id: "1", label: "Alice Johnson" }, { id: "t1", label: "urgent" }]

Imperative Handle

import { useRef } from "react";
import { Mentions, type MentionsHandle } from "@skyastrall/mentions-react";

function Editor() {
  const ref = useRef<MentionsHandle>(null);

  return (
    <>
      <Mentions ref={ref} triggers={triggers} />
      <button onClick={() => ref.current?.focus()}>Focus</button>
      <button onClick={() => ref.current?.clear()}>Clear</button>
      <button onClick={() => ref.current?.insertTrigger("@")}>Insert @</button>
    </>
  );
}
<script setup>
import { ref } from "vue";
import { Mentions } from "@skyastrall/mentions-vue";
import type { MentionsInstance } from "@skyastrall/mentions-vue";

const mentionsRef = ref<MentionsInstance | null>(null);
</script>

<template>
  <Mentions ref="mentionsRef" :triggers="triggers" />
  <button @click="mentionsRef?.focus()">Focus</button>
  <button @click="mentionsRef?.clear()">Clear</button>
  <button @mousedown.prevent="mentionsRef?.insertTrigger('@')">Insert @</button>
</template>
<script>
import { Mentions } from "@skyastrall/mentions-svelte";

let mentions;
</script>

<Mentions bind:this={mentions} {triggers} />
<button onclick={() => mentions.focus()}>Focus</button>
<button onclick={() => mentions.clear()}>Clear</button>
<button onmousedown={(e) => { e.preventDefault(); mentions.insertTrigger("@"); }}>
  Insert @
</button>

Next

Compound Components for custom layouts, or API Reference for full details.