Component

Mention

A text input component that triggers suggestions when typing a specified character, enabling inline mentions of users or items.

External Component

This component is provided by Dice UI. View the original documentation for full details.

'use client'

import * as React from 'react'
import {
  Mention,
  MentionInput,
  MentionContent,
  MentionItem,
  MentionLabel,
} from '@/components/ui/mention'

const MTPRZ_AVATAR = '/static/c/matiasperz.webp'
const JOYCO_AVATAR = '/static/c/joyco.webp'
const JOYBOY_AVATAR = '/static/c/joyboy.webp'
const FABROOS_AVATAR = '/static/c/fabroos.webp'

const users = [
  {
    id: '1',
    name: 'Matias Perez',
    username: 'matiasperz',
    avatar: MTPRZ_AVATAR,
  },
  { id: '2', name: 'Joyco', username: 'joyco', avatar: JOYCO_AVATAR },
  { id: '3', name: 'Joyboy', username: 'joyboy', avatar: JOYBOY_AVATAR },
  { id: '4', name: 'Fabroos', username: 'fabroos', avatar: FABROOS_AVATAR },
]
export function MentionDemo() {
  const [value, setValue] = React.useState<string[]>([])

  return (
    <Mention className="not-prose mx-auto w-full max-w-[400px] px-4 py-6">
      <MentionLabel>Mention someone</MentionLabel>
      <Mention trigger="@" value={value} onValueChange={setValue}>
        <MentionInput placeholder="Type @ to mention someone..." asChild>
          <textarea className="mt-2 min-h-[60px]" />
        </MentionInput>
        <MentionContent>
          {users.map((user) => (
            <MentionItem key={user.id} value={user.username}>
              <img
                src={user.avatar}
                alt={user.name}
                className="size-6 rounded-full"
              />
              <div className="flex flex-col">
                <span className="text-sm font-medium">{user.name}</span>
                <span className="text-muted-foreground text-xs">
                  @{user.username}
                </span>
              </div>
            </MentionItem>
          ))}
        </MentionContent>
      </Mention>
    </Mention>
  )
}

export default MentionDemo

Installation

pnpm dlx shadcn@latest add https://r.joyco.studio/mention.json

Usage

import {
  Mention,
  MentionInput,
  MentionList,
  MentionItem,
  MentionItemText,
} from '@/components/ui/mention'
 
<Mention>
  <MentionInput />
  <MentionList>
    <MentionItem>
      <MentionItemText />
    </MentionItem>
  </MentionList>
</Mention>

With Chat Component

Combine with the Chat component to enable mentions in a chat interface:

F
Hey @matiasperz, did you see the new component?
M
Yes! @joyboy and @joyco helped with the design
J
It's looking great! 🎉
'use client'

import * as React from 'react'
import {
  Chat,
  ChatInputArea,
  ChatInputSubmit,
  ChatViewport,
  ChatMessages,
  ChatMessageRow,
  ChatMessageBubble,
  ChatMessageTime,
  ChatMessageAvatar,
  ChatInputField,
  type ChatSubmitEvent,
} from '@/components/chat'
import { Mention, MentionContent, MentionItem } from '@/components/ui/mention'
import * as MentionPrimitive from '@diceui/mention'
import { ArrowUpIcon } from 'lucide-react'

const MTPRZ_AVATAR = '/static/c/matiasperz.webp'
const JOYCO_AVATAR = '/static/c/joyco.webp'
const JOYBOY_AVATAR = '/static/c/joyboy.webp'
const FABROOS_AVATAR = '/static/c/fabroos.webp'

const users = [
  {
    id: '1',
    name: 'Matias Perez',
    username: 'matiasperz',
    avatar: MTPRZ_AVATAR,
  },
  { id: '2', name: 'Joyco', username: 'joyco', avatar: JOYCO_AVATAR },
  { id: '3', name: 'Joyboy', username: 'joyboy', avatar: JOYBOY_AVATAR },
  { id: '4', name: 'Fabroos', username: 'fabroos', avatar: FABROOS_AVATAR },
]

type Message = {
  id: string
  avatar?: string
  name?: string
  fallback?: string
  content: string
  role: 'self' | 'peer'
  timestamp: Date
}

const initialChat: Message[] = [
  {
    id: '1',
    avatar: FABROOS_AVATAR,
    name: 'Fabroos',
    fallback: 'F',
    content: 'Hey @matiasperz, did you see the new component?',
    role: 'peer',
    timestamp: new Date('2025-12-26T01:00:00.000Z'),
  },
  {
    id: '2',
    avatar: MTPRZ_AVATAR,
    name: 'You',
    fallback: 'M',
    content: 'Yes! @joyboy and @joyco helped with the design',
    role: 'self',
    timestamp: new Date('2025-12-26T01:01:00.000Z'),
  },
  {
    id: '3',
    avatar: JOYBOY_AVATAR,
    name: 'Joyboy',
    fallback: 'J',
    content: "It's looking great! 🎉",
    role: 'peer',
    timestamp: new Date('2025-12-26T01:02:00.000Z'),
  },
]

function MentionHighlight({
  children,
  className,
}: {
  children: string
  className?: string
}) {
  const parts = children.split(/(@\w+)/g)

  return (
    <span className={className}>
      {parts.map((part, index) => {
        if (part.startsWith('@')) {
          return (
            <span
              key={index}
              className="rounded bg-blue-200 px-0.5 py-px text-blue-950 dark:bg-blue-800 dark:text-blue-50"
            >
              {part}
            </span>
          )
        }
        return part
      })}
    </span>
  )
}

export function ChatWithMentionDemo() {
  const [chat, setChat] = React.useState<Message[]>(initialChat)
  const [mentions, setMentions] = React.useState<string[]>([])
  const [input, setInput] = React.useState('')

  const handleSubmit = (e: ChatSubmitEvent) => {
    e.preventDefault()
    const userMessage: Message = {
      id: Date.now().toString(),
      avatar: MTPRZ_AVATAR,
      name: 'You',
      fallback: 'M',
      content: e.message,
      role: 'self',
      timestamp: new Date(),
    }

    setChat((prev) => [...prev, userMessage])
    setMentions([])
    setInput('')
  }

  return (
    <Chat onSubmit={handleSubmit}>
      <div className="mx-auto flex w-full max-w-2xl flex-col gap-4 px-4 py-6">
        <ChatViewport className="h-96">
          <ChatMessages className="w-full py-3">
            {chat.map((message) => (
              <ChatMessageRow key={message.id} variant={message.role}>
                <ChatMessageAvatar
                  src={message.avatar}
                  fallback={message.fallback}
                  alt={message.name}
                />
                <ChatMessageBubble>
                  <MentionHighlight>{message.content}</MentionHighlight>
                </ChatMessageBubble>
                <ChatMessageTime dateTime={message.timestamp} />
              </ChatMessageRow>
            ))}
          </ChatMessages>
        </ChatViewport>

        <ChatInputArea>
          <Mention
            trigger="@"
            inputValue={input}
            onInputValueChange={setInput}
            value={mentions}
            onValueChange={setMentions}
          >
            <MentionPrimitive.Input asChild>
              <ChatInputField
                placeholder="Type @ to mention someone..."
                multiline
              />
            </MentionPrimitive.Input>
            <MentionContent>
              {users.map((user) => (
                <MentionItem key={user.id} value={user.username}>
                  <img
                    src={user.avatar}
                    alt={user.name}
                    className="size-6 rounded-full"
                  />
                  <div className="flex flex-col">
                    <span className="text-sm font-medium">{user.name}</span>
                    <span className="text-muted-foreground text-xs">
                      @{user.username}
                    </span>
                  </div>
                </MentionItem>
              ))}
            </MentionContent>
          </Mention>
          <ChatInputSubmit disabled={input.length === 0}>
            <ArrowUpIcon className="size-[1.2em]" />
            <span className="sr-only">Send</span>
          </ChatInputSubmit>
        </ChatInputArea>
      </div>
      <style>{
        /* css */ `
        @layer utilities {
          .safe-field-sizing-content {
            height: 0;
          }

          @supports (field-sizing: content) {
            .safe-field-sizing-content {
              field-sizing: content;
              height: auto;
            }
          }
        }
      `
      }</style>
    </Chat>
  )
}

export default ChatWithMentionDemo
Downloads
0Total
0 downloads today