A React textarea component with @mention functionality and autosize
npm install mentions-textareabash
npm install mentions-textarea
or
yarn add mentions-textarea
or
pnpm add mentions-textarea
`
Basic Usage
`tsx
import { MentionsTextarea, MentionItem } from "mentions-textarea";
const users: MentionItem[] = [
{ id: "1", label: "John Doe", value: "john.doe" },
{ id: "2", label: "Jane Smith", value: "jane.smith" },
{ id: "3", label: "Bob Johnson", value: "bob.johnson" },
];
function App() {
const [value, setValue] = useState("");
return (
value={value}
onChange={setValue}
mentionItems={users}
placeholder="Type @ to mention someone..."
/>
);
}
`
Advanced Usage
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
showSubmitButton={true}
submitButtonText="Post Comment"
onSubmit={() => {
console.log("Posted:", value);
setValue("");
}}
/>
`
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
renderMentionItem={(item, isSelected) => (
src={item.avatar}
alt={item.label}
className="w-6 h-6 rounded-full"
/>
{item.label}
@{item.value}
)}
/>
`
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
className="my-custom-wrapper"
placeholder="Start typing..."
disabled={false}
loading={false}
/>
`
API Reference
$3
| Prop | Type | Default | Description |
| ------------------- | ------------------------------------------------------- | -------------------- | --------------------------------------- |
| value | string | - | Required. The textarea value |
| onChange | (value: string) => void | - | Required. Called when value changes |
| mentionItems | MentionItem[] | [] | Array of mentionable items |
| placeholder | string | "Add a comment..." | Textarea placeholder |
| disabled | boolean | false | Disable the textarea |
| loading | boolean | false | Show loading state |
| className | string | "" | Additional CSS classes |
| onKeyDown | (e: KeyboardEvent) => void | - | Custom keydown handler |
| onMentionSelect | (item: MentionItem) => void | - | Called when mention is selected |
| renderMentionItem | (item: MentionItem, isSelected: boolean) => ReactNode | - | Custom mention item renderer |
| showSubmitButton | boolean | false | Show submit button |
| submitButtonText | string | "Submit" | Submit button text |
| onSubmit | () => void \| Promise | - | Submit handler |
$3
`tsx
interface MentionItem {
id: string; // Unique identifier
label: string; // Display name
value: string; // Username/handle (without @)
avatar?: string; // Optional avatar URL
fallback?: string; // Optional fallback text
}
`
Styling Examples
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
className="w-full max-w-2xl"
placeholder="Type @ to mention someone..."
/>
`
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
className="form-control"
placeholder="Type @ to mention someone..."
/>
`
$3
`tsx
import styles from "./MentionsTextarea.module.css";
value={value}
onChange={setValue}
mentionItems={users}
className={styles.textarea}
/>;
`
$3
`tsx
import styled from "styled-components";
const StyledMentionsTextarea = styled(MentionsTextarea)
;
value={value}
onChange={setValue}
mentionItems={users}
/>;
`
Keyboard Navigation
- @ - Triggers mention suggestions
- Arrow Up/Down - Navigate through suggestions
- Enter/Tab - Select highlighted mention
- Escape - Close mention popup
- Any other key - Normal textarea behavior
Customization
$3
`tsx
const customMentions: MentionItem[] = [
{
id: "1",
label: "John Doe",
value: "john.doe",
avatar: "https://example.com/avatar1.jpg",
fallback: "JD",
},
{
id: "2",
label: "Jane Smith",
value: "jane.smith",
avatar: "https://example.com/avatar2.jpg",
fallback: "JS",
},
];
`
$3
`tsx
value={value}
onChange={setValue}
mentionItems={users}
renderMentionItem={(item, isSelected) => (
className={flex items-center gap-3 p-2 ${
}
>
{item.avatar ? (
src={item.avatar}
alt={item.label}
className="w-8 h-8 rounded-full"
/>
) : (
{item.fallback}
)}
{item.label}
@{item.value}
Real-world Examples
$3
`tsx
function ChatInput() {
const [message, setMessage] = useState("");
const [users] = useState([
{ id: "1", label: "Alice", value: "alice" },
{ id: "2", label: "Bob", value: "bob" },
]);
const handleSubmit = async () => {
await sendMessage(message);
setMessage("");
};
return (
value={message}
onChange={setMessage}
mentionItems={users}
placeholder="Type a message..."
showSubmitButton={true}
submitButtonText="Send"
onSubmit={handleSubmit}
/>
);
}
`
$3
`tsx
function CommentForm() {
const [comment, setComment] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async () => {
setIsSubmitting(true);
try {
await postComment(comment);
setComment("");
} finally {
setIsSubmitting(false);
}
};
return (
value={comment}
onChange={setComment}
mentionItems={users}
placeholder="Write a comment..."
showSubmitButton={true}
submitButtonText="Post Comment"
onSubmit={handleSubmit}
loading={isSubmitting}
/>
);
}
`
Browser Support
- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+
Dependencies
- React 18.0+ (hooks required). Ensure your app's React version matches the package build to avoid JSX runtime mismatches.
- react-textarea-autosize (peer dependency)
License
MIT
Contributing
1. Fork the repository
2. Create your feature branch (git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)