# mentis — full documentation > Accessible @mention autocomplete input for React. ContentEditable, zero dependencies, TypeScript-first — a modern react-mentions alternative. Package name: mentis Repository: https://github.com/alexanderdunlop/mentis Documentation: https://mentis.alexdunlop.com --- # Installation > You can install mentis via npm, yarn, pnpm, or bun. Source: https://mentis.alexdunlop.com/docs/installation Install the `mentis` package with your package manager of choice. ```shell npm install mentis ``` ```shell yarn add mentis ``` ```shell pnpm add mentis ``` ```shell bun add mentis ``` [npmjs.com](https://www.npmjs.com/package/mentis) --- # Overview > Introduction to the MentionInput component and its main features. Source: https://mentis.alexdunlop.com/docs/overview The `MentionInput` component is an accessible, customizable mention input solution designed for chat, comment, and editor interfaces where users need to mention others or reference entities quickly and intuitively. Built on a modern contentEditable architecture, it provides rich text capabilities with enhanced mention handling and DOM manipulation. **Main Features:** - **ContentEditable Architecture**: Modern implementation using contentEditable for rich text support and enhanced cursor navigation - **Smart Mention Detection**: DOM-aware mention detection that distinguishes between mentions inside chips versus regular text - **Flexible Trigger System**: Customizable trigger character or string (default `@`) via the `trigger` prop - **Enhanced Navigation**: Full keyboard navigation including arrow key navigation into mention chips - **Robust Text Handling**: Advanced mention insertion and parsing with comprehensive clipboard support - **Customizable Display**: Option to keep or remove the trigger character on selection (`keepTriggerOnSelect`) - **Slot-based Customization**: Comprehensive customization for container, contentEditable, modal, options, and more via `slotsProps` - **Zero Dependencies**: Lightweight implementation with no external dependencies - **Fully Accessible**: Complete ARIA roles and keyboard support for optimal accessibility - **Rich Text Support**: Display mentions as styled chips within the contentEditable interface - **Function Values**: Support for executable functions as option values for dynamic actions - **Auto-Conversion**: Optional automatic conversion of text mentions to chips when typing space or enter - **Advanced Paste Handling**: Intelligent parsing and conversion of mentions from pasted content --- # Basic usage > A minimal controlled MentionInput example in React, with options, displayValue, dataValue, and onChange. Source: https://mentis.alexdunlop.com/docs/basic-usage ```tsx import { MentionInput, type MentionData } from "mentis"; import "mentis/dist/index.css"; function App() { const [dataValue, setDataValue] = useState(""); const handleChange = (newValue: MentionData) => { setDataValue(newValue.dataValue); }; return ( ); } ``` --- # Options > How to structure and use the options prop for mentions. Source: https://mentis.alexdunlop.com/docs/options The `options` prop is an array of objects that define the available mention targets. Each option must have a `label` (displayed in the modal) and a `value` (unique identifier). ### Example ```tsx import { type MentionOption } from "mentis"; const options: MentionOption[] = [ { label: "Alice", value: "alice" }, { label: "Bob", value: "bob" }, { label: "Charlie", value: "charlie" }, ]; ``` - **label**: The text shown in the mention dropdown. - **value**: A unique string identifier for the option, or a function that will be called when the option is selected. ## Function Values You can also use functions as values for options. When a function is provided as the `value`, it will be called when the option is selected instead of inserting the mention into the input: ```tsx import { type MentionOption, MentionInput } from "mentis"; const options: MentionOption[] = [ { label: "Alice", value: "alice" }, { label: "Bob", value: "bob" }, { label: "Charlie", value: "charlie" }, { label: "Custom Action", value: () => { alert("Custom action executed!"); }, }, ]; ; ``` In this example, selecting "Custom Action" will trigger the function instead of inserting a mention chip into the input. The trigger character and any text typed after it will be automatically removed from the input. --- # Chips > Understanding mention chips and their role in the MentionInput component. Source: https://mentis.alexdunlop.com/docs/chips # Mention Chips Mention chips are the visual representation of selected mentions within the `MentionInput` component. They transform plain text mentions into styled, interactive elements that provide better visual feedback and user experience. ## What are Chips? Chips are `` elements with the class `mention-chip` that replace text-based mentions in the contentEditable interface. They serve several important purposes: - **Visual Distinction**: Chips are styled differently from regular text to clearly indicate they represent mentions - **Data Storage**: Each chip contains metadata about the mentioned entity via `data-*` attributes - **Interactive Elements**: Chips can be navigated with keyboard and provide rich interaction - **Content Protection**: Chips are set to `contentEditable="false"` to prevent accidental editing ## Chip Structure When a mention is selected, it's converted into a chip with this structure: ```html @John Doe ``` ### Chip Attributes | Attribute | Purpose | Example | | ------------------------- | ---------------------------------------------------- | -------------- | | `class="mention-chip"` | Identifies the element as a mention chip | `mention-chip` | | `contenteditable="false"` | Prevents editing of the chip content | `false` | | `data-value` | Stores the unique identifier of the mentioned entity | `user123` | | `data-label` | Stores the display name of the mentioned entity | `John Doe` | ## Chip Creation Chips are created in several scenarios: ### 1. Manual Selection When a user selects an option from the dropdown, a chip is immediately created: ```tsx ``` ### 2. Auto-Conversion When `autoConvertMentions` is enabled, text mentions are automatically converted to chips when the user types a space or presses Enter: ```tsx ``` ### 3. Paste Operations When pasting text containing mentions, the component automatically parses and converts them to chips: ```tsx // Pasting "@Alice @Bob" will create chips for both mentions ``` ## Chip Styling Chips come with default styling: ```css .mention-chip { display: inline-block; background: #007bff; color: white; padding: 0px 4px; border-radius: 4px; } ``` ### Customizing Chip Styles You can customize the appearance of chips using the `chipClassName` property in `slotsProps`: ```tsx ``` ```tsx ``` This allows you to apply a custom CSS class to the chip elements. For more advanced styling examples, see the [Styling & Customization](./styling) page. ## Chip Behavior ### Keyboard Navigation Chips support full keyboard navigation: - **Arrow Keys**: Navigate through chips and text - **Backspace/Delete**: Remove chips when cursor is adjacent - **Click**: Position cursor before or after the chip ### Chip Deletion on Input When a user clicks inside a chip and starts typing, the chip is automatically deleted and replaced with the typed text. This provides an intuitive way to edit or remove mentions: ```tsx // User clicks inside "@John Doe" chip and types "X" // Result: "@John DoeX" (chip is deleted, "X" is not inserted) ``` This behavior ensures that: - Users can easily modify or remove mentions by typing over them - The component maintains data integrity by removing the mention from the data structure - The `onChange` callback is triggered with updated mention data - The text becomes fully editable after chip deletion ### Trigger Character Display The `keepTriggerOnSelect` prop controls whether the trigger character is included in the chip: ```tsx // With keepTriggerOnSelect: true (default) @Alice // With keepTriggerOnSelect: false Alice ``` ### Interactive Example Try the following interactions in the demo above: 1. **Create a chip**: Type `@` and select a user from the dropdown 2. **Delete by typing**: Click inside the chip and start typing - the chip will be deleted 3. **Edit mentions**: Click inside any chip and modify the text to see the chip deletion in action Chips are a fundamental part of the MentionInput component that enhance user experience by providing clear visual feedback and maintaining data integrity for mentions within your application. --- # Styling & Customization > Style the mentis MentionInput with Tailwind, CSS modules, or plain CSS using the slotsProps class names for each slot. Source: https://mentis.alexdunlop.com/docs/styling The `MentionInput` component is designed to be fully customizable. You can use Tailwind CSS, your own CSS classes, or any CSS framework by passing className values for each part of the component via the `slotsProps` object. This flexible approach allows you to match the look and feel of your application or design system. ## Customizing with className You can customize the appearance of each part of the `MentionInput` component by passing a `slotsProps` object. This object lets you specify a `className` for each slot: - `container`: The outer container - `contentEditable`: The contentEditable element for rich text input - `modal`: The dropdown list container - `option`: Each option in the list - `chipClassName`: The CSS class name for mention chips that appear in the input - `highlightedClassName`: Applied to the currently highlighted option - `noOptions`: The element shown when there are no options For each slot (except `highlightedClassName` and `chipClassName`), pass an object with a `className` property. For `highlightedClassName` and `chipClassName`, pass a string with the class name to apply. ## Example: Default Styles To use the default styles that come with mentis, simply import the CSS file: ```tsx import { MentionInput } from "mentis"; import "mentis/dist/index.css"; ; ``` This will apply the default styling to all parts of the component without any additional configuration. ## Example: Custom CSS with className Here's an example using your own CSS classes (see `index.css` for definitions): ```tsx ``` This approach gives you complete control over the component's appearance using your own CSS. You can define these classes in your project's CSS file (for example, `index.css`). --- ## Example: Tailwind CSS Here's an example using Tailwind CSS utility classes directly in the `slotsProps`: ```tsx ``` This approach lets you style the component using Tailwind's utility classes for rapid prototyping and design consistency. ## Chip Styling Considerations When styling mention chips, pay special attention to **line-height and padding** to prevent layout shifting: ### Line-Height Matching Chips are inline elements that flow with text content. To maintain consistent text alignment and prevent vertical layout shifts, ensure your chip's total height (including padding) matches the line-height of your text: --- For more advanced usage, see the [Props Reference](./props) and [Basic Usage](./basic-usage) pages. --- # Props Reference > Detailed documentation of MentionInput component props. Source: https://mentis.alexdunlop.com/docs/props ## Props | Name | Type | Required | Description | | ------------------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | | displayValue | string | No | The current display value of the input (what user sees). | | dataValue | string | No | Data value for programmatic control (mention IDs). When provided, reconstructs mentions from data values. | | options | MentionOption[] | Yes | Array of mentionable options. See [Options](./options) for more. | | slotsProps | SlotProps | No | Customization for internal component slots (see below). | | keepTriggerOnSelect | boolean | No | Whether to keep the trigger character (e.g. '@') when an option is selected. Defaults to true. | | trigger | string | No | The character or string that triggers the mention dropdown. Defaults to '@'. | | autoConvertMentions | boolean | No | Whether to automatically convert text mentions to chips when typing space or enter. Defaults to false. | | onChange | (value: MentionData) => void | No | Callback fired when the input value changes with structured mention data. | | onKeyDown | (event: KeyboardEvent) => void | No | Callback fired when a key is pressed. Note: Some keys (Enter, Tab, Escape, Arrow keys) are handled internally when the modal is open. | ### MentionOption ```tsx type MentionOption = { label: string; value: string | Function; // Can be a string identifier or executable function }; ``` ### SlotProps The `slotsProps` prop allows you to customize the internal elements of the MentionInput. All properties are optional. ```tsx type SlotProps = Partial<{ container: React.HTMLAttributes; // Props for the outer container contentEditable: Omit< React.HTMLAttributes, | "ref" | "contentEditable" | "suppressContentEditableWarning" | "onInput" | "onKeyDown" | "onFocus" | "onBlur" | "onPaste" | "role" | "aria-controls" | "aria-activedescendant" | "aria-haspopup" | "aria-autocomplete" | "aria-expanded" >; // Props for the contentEditable element modal: Omit, "id" | "role" | "style">; // Props for the dropdown listbox option: Omit< React.HTMLAttributes, "id" | "key" | "role" | "style" | "aria-selected" | "onMouseDown" >; // Props for each option noOptions: React.HTMLAttributes; // Props for the 'No items found' message highlightedClassName: string; // Custom class for the highlighted option chipClassName: string; // Custom class for mention chips }>; ``` - `container`: Props for the outer `
` container. - `contentEditable`: Props for the contentEditable `
` element (excluding controlled props for mention functionality). - `modal`: Props for the dropdown listbox container. - `option`: Props for each option in the dropdown. - `noOptions`: Props for the 'No items found' message. - `highlightedClassName`: Custom class for the currently highlighted option. - `chipClassName`: Custom class for mention chips displayed in the input. --- ### `keepTriggerOnSelect` If `true` (default), the trigger character (such as `@`) will be kept in the input when an option is selected. If `false`, the trigger character will be removed before the selected label. ```tsx ``` --- ### `trigger` The `trigger` prop allows you to customize which character or string opens the mention dropdown. By default, this is set to `@`, but you can use any character (e.g., `#`) or even a multi-character string (e.g., `::`). ```tsx ``` This will open the mention dropdown when the user types `#` instead of `@`. --- ### `autoConvertMentions` When `true`, the component will automatically convert text mentions to chips when the user types a space or presses Enter. This is useful for scenarios where users type mentions manually without selecting from the dropdown. ```tsx ``` **How it works:** - When enabled, the component monitors for space characters and Enter key presses - It scans the text for patterns like `@username` that match your options - Matching text is automatically converted to chips - The conversion happens asynchronously to ensure DOM updates are complete - This feature works independently of the paste functionality, which has its own mention parsing **⚠️ Performance Warning:** This feature is not enabled by default as it requires additional performance testing in production environments. The automatic conversion process runs on every space/enter key press and may impact performance with large option lists or frequent typing. --- ### `onKeyDown` The `onKeyDown` prop allows you to handle keyboard events in the MentionInput. This is useful for implementing custom keyboard shortcuts, form submission, or other keyboard-based interactions. **Important:** When the mention modal is open, certain keys are handled internally by the component and won't trigger your `onKeyDown` callback: - `Enter` and `Tab` - Used for selecting options - `Escape` - Used for closing the modal - `ArrowUp` and `ArrowDown` - Used for navigation ```tsx { // Handle custom keyboard shortcuts if (event.ctrlKey && event.key === "s") { event.preventDefault(); alert("Ctrl + S"); } }} /> ``` #### Form Submission Example Here's how to handle form submission when the user presses Enter (but only when the modal is closed): ```tsx import { useState } from "react"; import { MentionInput } from "mentis"; function ChatForm() { const [displayValue, setDisplayValue] = useState(""); const handleSubmit = async () => { console.log("submit"); setDisplayValue(""); }; return (
e.preventDefault()}> setDisplayValue(mentionData.displayValue)} onKeyDown={(event) => { // Handle Enter key for form submission if (event.key === "Enter") { event.preventDefault(); handleSubmit(); } }} options={[ { label: "Alice", value: "alice" }, { label: "Bob", value: "bob" }, { label: "Charlie", value: "charlie" }, ]} /> ); } ``` In this example: - The `onKeyDown` handler checks if the Enter key was pressed - The component automatically handles Enter for mention selection when the modal is open - When the modal is closed, Enter will trigger the form submission - The component's internal handling takes precedence over custom handlers #### Keyboard Shortcuts Example You can also implement custom keyboard shortcuts: ```tsx { // Ctrl/Cmd + Enter to submit if ((event.ctrlKey || event.metaKey) && event.key === "Enter") { event.preventDefault(); handleSubmit(); } // Ctrl/Cmd + K to focus if ((event.ctrlKey || event.metaKey) && event.key === "k") { event.preventDefault(); inputRef.current?.focus(); } }} /> ``` --- ### Function Values Options can have function values that execute when selected. This is useful for actions like sending messages, clearing input, or triggering other side effects: ```tsx console.log("Message sent!") }, { label: "Clear Input", value: () => setDisplayValue("") }, { label: "Alice", value: "alice" }, ]} /> ``` When a function value is selected: - The trigger and query text are removed from the input - The function is executed - The modal is closed - No mention data is added to the input --- # onChange Callback > How the mentis onChange callback works: the MentionData object, displayValue vs dataValue, and the mentions array. Source: https://mentis.alexdunlop.com/docs/onchange The `onChange` callback in Mentis provides you with both the display text and structured mention data. This allows you to access the actual mention values for processing, validation, or API calls. **Key Difference:** - `displayValue`: Shows mention labels (what users see, e.g., "@Alice") - `dataValue`: Shows mention values (actual data, e.g., "user_123") ## Callback Signature The `onChange` callback receives a `MentionData` object: ```tsx type MentionData = { displayValue: string; // The text as displayed in the input (shows mention labels) dataValue: string; // The text with mention values (shows actual data) mentions: Array<{ label: string; // The display label of the mention value: string; // The actual value of the mention startIndex: number; // Position where the mention starts in the text endIndex: number; // Position where the mention ends in the text }>; }; ``` ## Basic Usage ```tsx import { MentionInput, type MentionData } from "mentis"; function App() { const [mentionData, setMentionData] = useState(null); const handleChange = (newValue: MentionData) => { setMentionData(newValue); // Access mention values const mentionValues = newValue.mentions.map((mention) => mention.value); console.log("Mention values:", mentionValues); }; return ( ); } ``` ## Example: Processing Mentions Here's how you might use the structured data to process mentions: ```tsx const handleChange = (newValue: MentionData) => { // displayValue shows what the user sees (e.g., "Hello @Alice and @Bob") console.log("Display text:", newValue.displayValue); // dataValue shows the actual values (e.g., "Hello user_123 and user_456") console.log("Data value:", newValue.dataValue); // Extract user IDs for API calls const userIds = newValue.mentions.map((mention) => mention.value); // Send to API if (userIds.length > 0) { notifyUsers(userIds); } // Validate mentions const validMentions = newValue.mentions.filter((mention) => mention.value.startsWith("user_") ); if (validMentions.length !== newValue.mentions.length) { console.warn("Some mentions are invalid"); } }; ``` ## When You Get Structured Data The `onChange` callback always provides structured `MentionData` when: - A mention is selected from the dropdown - Text is pasted that contains mentions - Mentions are auto-converted (when `autoConvertMentions` is true) - The input content changes (even when empty or with only plain text) --- # Accessibility > Accessibility features and ARIA support in MentionInput. Source: https://mentis.alexdunlop.com/docs/accessibility The `MentionInput` component is designed with accessibility in mind: - Uses `role="combobox"` for the contentEditable element and `role="listbox"`/`role="option"` for the dropdown and options. - Supports comprehensive keyboard navigation including arrow key navigation into mention chips (see [Keyboard Navigation](./keyboard-navigation)). - Uses `aria-controls`, `aria-activedescendant`, `aria-autocomplete`, `aria-haspopup`, and `aria-expanded` for screen reader support. - Focus is managed when selecting options and navigating with contentEditable. - The modal can be closed with `Escape` for easy dismissal. - ContentEditable implementation provides enhanced text manipulation and cursor positioning for screen readers. These features ensure the component is usable by keyboard and assistive technology users, with the contentEditable architecture providing improved accessibility for rich text interactions. --- # Keyboard Navigation > How to use keyboard controls when the mention modal is open. Source: https://mentis.alexdunlop.com/docs/keyboard-navigation import { Suspense } from "react"; When you trigger the mention modal by typing @ (or your custom trigger), you can use the following keyboard controls to navigate and select options: - Up Arrow / Down Arrow: Move the selection up or down in the list. - Enter or Tab: Select the currently highlighted option. - Escape (Esc): Close the modal without making a selection. - Left Arrow / Right Arrow: Navigate into mention chips for enhanced text editing. This allows for fast, accessible navigation and selection of mention options using only the keyboard. The contentEditable architecture provides enhanced cursor navigation, including the ability to navigate into existing mention chips with the left arrow key. ## Custom Keyboard Handling You can add custom keyboard event handling using the `onKeyDown` prop. This is useful for implementing form submission, keyboard shortcuts, or other custom interactions. ```tsx { // Handle form submission with Enter if (event.key === "Enter") { event.preventDefault(); handleSubmit(); } // Custom keyboard shortcuts if (event.ctrlKey && event.key === "s") { event.preventDefault(); saveContent(); } }} /> ``` **Note:** When the mention modal is open, the component handles Enter, Tab, Escape, and arrow keys internally for navigation and selection. Your `onKeyDown` handler will not be called for these keys when the modal is active. --- # Examples > Runnable mentis example apps: plain React, custom CSS, Tailwind, Next.js, and the Vercel AI SDK. Source: https://mentis.alexdunlop.com/docs/examples Explore various usage examples for this library. You can find all examples in the following directory: - [simple](https://github.com/Alexanderdunlop/mentis/tree/main/packages/examples/simple) - [styling](https://github.com/Alexanderdunlop/mentis/tree/main/packages/examples/styling) - [tailwind](https://github.com/Alexanderdunlop/mentis/tree/main/packages/examples/tailwind) - [nextjs](https://github.com/Alexanderdunlop/mentis/tree/main/packages/examples/nextjs) - [nextjs-ai-sdk](https://github.com/Alexanderdunlop/mentis/tree/main/packages/examples/nextjs-ai-sdk) --- # LLM Context > Comprehensive context about the mentis library for AI assistants and LLMs Source: https://mentis.alexdunlop.com/docs/llm # Mentis Library Context for LLMs This document provides comprehensive context about the `mentis` library for AI assistants and LLMs to understand the codebase architecture, features, and implementation details. Machine-readable versions of the full documentation are available at [`/llms.txt`](https://mentis.alexdunlop.com/llms.txt) and [`/llms-full.txt`](https://mentis.alexdunlop.com/llms-full.txt). ## Overview **Mentis** is a modern React library for implementing mention/tagging functionality in text inputs. It's designed to be flexible, accessible, and highly customizable with support for both string and function values. Install it as `mentis` (not `@mentis/react`) and import the stylesheet alongside the component: ```tsx import { MentionInput } from "mentis"; import "mentis/dist/index.css"; ``` It is commonly reached for as a maintained alternative to `react-mentions`, whose last release was 4.4.10 in June 2023 and whose GitHub repository is no longer reachable. `react-mentions` is built on a `