Compound Components
Control layout while the library handles state, ARIA, and keyboard navigation.
Basic Structure
import { Mentions } from "@skyastrall/mentions-react";
<Mentions triggers={triggers}>
<Mentions.Editor placeholder="Type @..." className="my-editor" />
<Mentions.Portal>
<Mentions.List>
<Mentions.Item />
</Mentions.List>
</Mentions.Portal>
</Mentions> <script setup>
import {
Mentions, MentionsEditor, MentionsPortal,
MentionsList, MentionsItem,
} from "@skyastrall/mentions-vue";
</script>
<template>
<Mentions :triggers="triggers">
<MentionsEditor placeholder="Type @..." class="my-editor" />
<MentionsPortal>
<MentionsList>
<MentionsItem />
</MentionsList>
</MentionsPortal>
</Mentions>
</template> <script>
import {
Mentions, MentionsEditor, MentionsPortal,
MentionsList, MentionsItem,
} from "@skyastrall/mentions-svelte";
</script>
<Mentions {triggers}>
<MentionsEditor placeholder="Type @..." class="my-editor" />
<MentionsPortal>
<MentionsList>
<MentionsItem />
</MentionsList>
</MentionsPortal>
</Mentions> Custom Item Rendering
<Mentions.Item render={({ item, highlighted }) => (
<div style={{
display: "flex",
alignItems: "center",
gap: 8,
fontWeight: highlighted ? 600 : 400,
}}>
<img src={item.avatar} width={24} height={24} style={{ borderRadius: "50%" }} />
<div>
<div>{item.label}</div>
<div style={{ fontSize: 12, opacity: 0.6 }}>{item.role}</div>
</div>
</div>
)} /> <MentionsItem v-slot="{ item, highlighted }">
<div :style="{
display: 'flex',
alignItems: 'center',
gap: '8px',
fontWeight: highlighted ? 600 : 400,
}">
<img :src="item.avatar" width="24" height="24" style="border-radius: 50%" />
<div>
<div>{{ item.label }}</div>
<div style="font-size: 12px; opacity: 0.6">{{ item.role }}</div>
</div>
</div>
</MentionsItem> <MentionsItem>
{#snippet children({ item, highlighted })}
<div style:display="flex" style:align-items="center" style:gap="8px"
style:font-weight={highlighted ? 600 : 400}>
<img src={item.avatar} width="24" height="24" style="border-radius: 50%" />
<div>
<div>{item.label}</div>
<div style="font-size: 12px; opacity: 0.6">{item.role}</div>
</div>
</div>
{/snippet}
</MentionsItem> Loading and Empty States
<Mentions.List>
<Mentions.Loading>
<Spinner /> Searching...
</Mentions.Loading>
<Mentions.Empty>
No results found
</Mentions.Empty>
<Mentions.Item render={({ item }) => item.label} />
</Mentions.List> <MentionsList>
<MentionsLoading>
<Spinner /> Searching...
</MentionsLoading>
<MentionsEmpty>
No results found
</MentionsEmpty>
<MentionsItem />
</MentionsList> <MentionsList>
<MentionsLoading>
<Spinner /> Searching...
</MentionsLoading>
<MentionsEmpty>
No results found
</MentionsEmpty>
<MentionsItem />
</MentionsList> Portal Container
By default, the dropdown renders inline inside the component. To portal elsewhere:
<Mentions.Portal container={document.body}>
<Mentions.List>...</Mentions.List>
</Mentions.Portal> <MentionsPortal to="body">
<MentionsList>...</MentionsList>
</MentionsPortal> <!-- Svelte portal renders inline with fixed positioning -->
<MentionsPortal>
<MentionsList>...</MentionsList>
</MentionsPortal>