Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

hbmartin/react-mentions-ts

Repository files navigation

React Mentions TS

npm version CI npm bundle size TypeScript React Context7 Ask DeepWiki

A React component that enables Facebook/Twitter-style @mentions and tagging in textarea inputs with full TypeScript support.

🎯 Features

  • βœ… Flexible Triggers - Use any character or pattern to trigger mentions (@, #, :, or custom)
  • 🎨 Tailwind v4 Ready - First-class support for Tailwind CSS v4 utility styling
  • ⚑ Async Data Loading - Load suggestions dynamically from APIs
  • πŸ” Smart Suggestions - Real-time filtering and matching
  • β™Ώ Accessible - Built with ARIA labels and keyboard navigation
  • 🎯 TypeScript First - Written in TypeScript with complete type definitions
  • πŸ§ͺ Well Tested - Comprehensive test suite with Testing Library
  • 🌐 SSR Compatible - Works with Next.js and other SSR frameworks
  • πŸ“± Mobile Friendly - Touch-optimized for mobile devices

πŸ“¦ Installation

# npm
npm install react-mentions-ts --save
# yarn
yarn add react-mentions-ts
# pnpm
pnpm add react-mentions-ts

React Mentions TS uses peer dependencies for its styling helpers and React runtime. Ensure these are installed in your application (skip any you already have):

# npm
npm install class-variance-authority clsx react react-dom tailwind-merge
# yarn
yarn add class-variance-authority clsx react react-dom tailwind-merge
# pnpm
pnpm add class-variance-authority clsx react react-dom tailwind-merge

Check package.json for the latest peer dependency version ranges.

πŸš€ Quick Start

Add a MentionsInput with Mention children

import { useState } from 'react'
import { MentionsInput, Mention } from 'react-mentions-ts'
function MyComponent() {
 const [value, setValue] = useState('')
 return (
 <MentionsInput value={value} onMentionsChange={({ value: nextValue }) => setValue(nextValue)}>
 <Mention trigger="@" data={users} renderSuggestion={(entry) => <div>{entry.display}</div>} />
 <Mention trigger="#" data={tags} />
 </MentionsInput>
 )
}

Configure boilerplate tailwind styling in your styles/tailwind.css

@import "tailwindcss";
(...)
@import "react-mentions-ts/styles/tailwind.css";

πŸ’‘ How It Works

MentionsInput is the main component that renders the textarea control. It accepts one or multiple Mention components as children. Each Mention component represents a data source for a specific class of mentionable objects:

  • πŸ‘₯ Users - @username mentions
  • 🏷️ Tags - #hashtag mentions
  • πŸ“‹ Templates - {{variable}} mentions
  • 🎭 Emojis - :emoji: mentions
  • ✨ Custom - Any pattern you need!

View more examples

βš™οΈ Configuration

MentionsInput Props

The MentionsInput component supports the following props:

Prop name Type Default value Description
value string '' The value containing markup for mentions
onChange function (event) undefined Standard React change event fired by the underlying input. Note: event.target.value may not reflect the final state if a mention is modified. Use onMentionsChange for the canonical values.
onMentionsChange function ({ trigger, value, plainTextValue, mentions, previousValue }) undefined Called when the mention markup changes; receives the updated markup value, plain text, active mentions, and the previous markup value
onKeyDown function (event) empty function A callback that is invoked when the user presses a key in the mentions input
singleLine boolean false Renders a single line text input instead of a textarea, if set to true
onBlur function (event) undefined Invoked when the underlying input loses focus
onMentionBlur function (event, clickedSuggestion) undefined Receives an extra clickedSuggestion flag when focus left via the suggestions list
suggestionsPortalHost DOM Element undefined Render suggestions into the DOM in the supplied host element.
inputRef React ref undefined Accepts a React ref to forward to the underlying input element
suggestionsPlacement 'auto' | 'above' | 'below' 'below' Controls where the suggestion list renders relative to the caret ('auto' flips when space is limited)
a11ySuggestionsListLabel string '' This label would be exposed to screen readers when suggestion popup appears
customSuggestionsContainer function(children) empty function Allows customizing the container of the suggestions
inputComponent React component undefined Allows the use of a custom input component
suggestionsDisplay 'overlay' | 'inline' 'overlay' Choose between the traditional suggestions overlay and inline autocomplete hints
ignoreAccents boolean false Ignores any accents on letters during search if set to true
spellCheck boolean false Controls browser spell checking on the underlying input (disabled by default)
onSelect function (event) empty function A callback that is invoked when the user selects a portion of the text in the input

onMentionsChange payload

onMentionsChange receives an object with the following fields:

  • value: the latest markup string containing mentions
  • plainTextValue: the same content without mention markup
  • mentions: the mention occurrences extracted from the new value
  • previousValue: the markup string before the change
  • trigger: metadata about what caused the change. trigger.type is one of 'input', 'paste', 'cut', 'mention-add', or 'mention-remove', and, when available, trigger.nativeEvent references the originating DOM event (optional; do not rely on its exact shape). Regular text edits (typing, Backspace/Delete) use trigger.type: 'input'.

Mention Props

Each data source is configured using a Mention component, which has the following props:

Prop name Type Default value Description
trigger RegExp or string '@' Defines the char sequence upon which to trigger querying the data source
data array or function (search, callback) null An array of the mentionable data entries (objects with id & display keys, or a filtering function that returns an array based on a query parameter
renderSuggestion function (entry, search, highlightedDisplay, index, focused) null Allows customizing how mention suggestions are rendered (optional)
allowSpaceInQuery boolean false Permit spaces within the search query portion after the trigger (useful for multi-word names)
markup string | MentionSerializer '@[__display__](__id__)' Template string for stored markup, or pass a MentionSerializer instance for full control
displayTransform function (id, display) returns display Accepts a function for customizing the string that is displayed for a mention
onAdd function (id, display, startPos, endPos) empty function Callback invoked when a suggestion has been added (optional)
appendSpaceOnAdd boolean false Append a space when a suggestion has been added (optional)

Need the legacy markup customization? Import createMarkupSerializer from react-mentions and pass markup={createMarkupSerializer(':__id__')} (or any other template) to keep markup/parse logic in sync without wiring a regex manually.

πŸ”„ Async Data Loading

If a function is passed as the data prop, it receives the current search query and should return a promise that resolves with the list of suggestions.

type User = { id: string; display: string }
const fetchUsers = async (query: string): Promise<User[]> => {
 const response = await fetch(`/api/users?search=${query}`)
 return response.json()
}
<Mention trigger="@" data={fetchUsers} />

🎨 Styling

React Mentions ships its markup with Tailwind utility classes. Consumers should have Tailwind configured in their application build so these classes compile to real CSS. If you do not use Tailwind you can still provide your own styles via className, CSS modules, or inline styles.

Tailwind CSS

The components assume Tailwind is available in the consuming app. A minimal setup looks like:

// tailwind.config.js
module.exports = {
 content: ['./src/**/*.{js,ts,jsx,tsx}'],
 theme: { extend: {} },
 plugins: [],
}
/* src/index.css (or your global stylesheet) */
@import "tailwindcss";
@import "react-mentions-ts/styles/tailwind.css";

The optional helper react-mentions-ts/styles/tailwind.css only declares an @source "../dist"; directive so Tailwind v4 can detect the library's utility classes inside node_modules/react-mentions-ts/dist. Including it keeps your Tailwind config clean and avoids adding explicit content globs for the package.

If you are still on Tailwind v3, add ./node_modules/react-mentions-ts/dist/**/*.{js,jsx,ts,tsx} to the content array instead of importing the helper file.

Inline Styles

<MentionsInput style={customStyle}>
 <Mention style={mentionStyle} />
</MentionsInput>

When suggestionsDisplay="inline", override the inlineSuggestion style slot to customize the inline hint (the default demo style lives in demo/src/examples/defaultStyle.ts).

See demo/src/examples/defaultStyle.ts for examples.

CSS

Simply assign a className prop to MentionsInput. All DOM nodes will receive derived class names:

<MentionsInput className="mentions">
 <Mention className="mentions__mention" />
</MentionsInput>

πŸ§ͺ Testing

Due to React Mentions' internal cursor tracking, use @testing-library/user-event for realistic event simulation:

import { render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
test('mentions work correctly', async () => {
 const user = userEvent.setup()
 const { getByRole } = render(<MyMentionsComponent />)
 await user.type(getByRole('textbox'), '@john')
 // assertions...
})

🀝 Contributing

  • Contributions are welcome! If you want to contribute, first of all: thank you! ❀️
  • Please check out our Contributing Guide for guidelines about how to proceed.
  • React Mentions is licensed under the BSD-3-Clause License.

πŸ™ Acknowledgments

This project is a TypeScript rewrite and modernization of the original react-mentions library.

Contributors to react-mentions-ts

Made with contrib.rocks.

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /