GitHub - getnao/prompt-mentions

7 min read Original article β†—

A beautiful React component library for building AI prompts with @mentions. Features a sleek mention menu, nested submenus, keyboard navigation, custom theming, and file extension icons.

npm version MIT License

Features

  • 🎨 Multiple preset themes β€” Light, Cursor Dark, GitHub Dark, Minimal
  • 🎯 Multiple trigger characters β€” Use @, #, /, or any character
  • πŸ“ Nested menus β€” Navigate hierarchical options with Tab/Escape
  • ⌨️ Full keyboard navigation β€” Arrow keys, Enter, Tab, Escape
  • 🏷️ Mention pills β€” Beautiful styled tags for selected mentions
  • πŸ–ΌοΈ Icons custom and auto β€” Add icons to menu items, mentions. File extension icons are supported.
  • πŸŽ›οΈ Imperative API β€” Programmatically append mentions via ref
  • πŸ“± Message component β€” Render sent messages with formatted mentions
  • 🎨 Fully CSS customizable β€” CSS variables and theme objects

Installation

npm install prompt-mentions

Quick Start

import { Prompt } from "prompt-mentions";
import "prompt-mentions/style.css";

const options = [
  { id: "alice", label: "Alice Johnson" },
  { id: "bob", label: "Bob Smith" },
  { id: "main-ts", label: "main.ts" },
];

function App() {
  return (
    <Prompt
      placeholder="Type @ to mention..."
      mentionConfigs={[{ trigger: "@", options }]}
      onChange={(value, mentions) => {
        console.log("Value:", value);
        console.log("Mentions:", mentions);
      }}
    />
  );
}

Components

<Prompt />

The main input component with mention support.

import { Prompt } from "prompt-mentions";

Props

Prop Type Default Description
initialValue string "" Initial text content with optional mentions in @[id] format
placeholder string "" Placeholder text when input is empty
mentionConfigs MentionConfig[] [{ trigger: '@', options: [] }] Array of mention trigger configurations
theme PresetThemeName | PromptTheme β€” Theme preset name or custom theme object
className string "" Additional CSS class name
style CSSProperties β€” Inline styles
extensionIcons boolean false Auto-add file icons based on extension
onChange (value: string, mentions: SelectedMention[]) => void β€” Called on every text change
onEnter (value: string, mentions: SelectedMention[]) => void β€” Called when Enter is pressed
onMentionAdded (mention: SelectedMention) => void β€” Called when a mention is selected
onMentionDeleted (mention: SelectedMention) => void β€” Called when a mention is removed
onMentionClick (mention: SelectedMention) => void β€” Called when a mention pill is clicked

MentionConfig

interface MentionConfig {
  trigger: string; // Character that triggers the menu (e.g., '@', '#', '/')
  options: MentionOption[]; // Array of mention options
  menuPosition?: "above" | "below"; // Menu position relative to cursor
  showTrigger?: boolean; // Show trigger character in pill (default: false)
}

MentionOption

interface MentionOption {
  id: string; // Unique identifier
  label: string; // Display text
  icon?: ReactNode; // Optional icon component
  type?: "item" | "divider" | "title"; // Item type
  children?: MentionOption[]; // Nested submenu items
  labelRight?: string; // Secondary label (e.g., file path)
  indent?: number; // Visual indent level
}

<Message />

Display sent messages with formatted mention pills.

import { Message } from "prompt-mentions";

<Message
  value="Hello @[alice]! Please review @[main-ts]"
  mentionConfigs={[{ trigger: "@", options }]}
  onMentionClick={(mention) => console.log("Clicked:", mention)}
/>;

Props

Prop Type Default Description
value string β€” Message text with mentions in trigger[id] format
mentionConfigs MessageMentionConfig[] [{ trigger: '@' }] Mention configurations for label/icon lookup
theme PresetThemeName | PromptTheme β€” Theme preset or custom theme
className string "" Additional CSS class name
style CSSProperties β€” Inline styles
extensionIcons boolean false Auto-add file icons based on extension
onMentionClick (mention) => void β€” Called when a mention pill is clicked

Theming

Preset Themes

<Prompt theme="light" />       // Default light theme
<Prompt theme="cursorDark" />  // Cursor IDE dark theme
<Prompt theme="githubDark" />  // GitHub dark theme
<Prompt theme="minimal" />     // Clean minimal theme

Custom Theme

Pass a PromptTheme object for full control:

const customTheme: PromptTheme = {
  backgroundColor: "#1a1625",
  color: "#e0d4f7",
  placeholderColor: "#6b5b8c",
  fontSize: "14px",
  borderRadius: "12px",
  borderColor: "#2d2640",
  focusBorderColor: "#9c6ade",

  menu: {
    backgroundColor: "#1a1625",
    borderColor: "#2d2640",
    color: "#c4b5dc",
    itemHoverColor: "#2d2640",
  },

  pill: {
    backgroundColor: "linear-gradient(135deg, #7c3aed, #c026d3)",
    borderRadius: "8px",
    color: "white",
  },
};

<Prompt theme={customTheme} />;

Partial Overrides

Override only specific properties:

<Prompt
  theme={{
    focusBorderColor: "#f43f5e",
    pill: {
      backgroundColor: "#16a34a",
    },
  }}
/>

CSS Variables

All styling is controlled via CSS variables. Override them in your CSS:

.prompt-container {
  --prompt-background-color: white;
  --prompt-color: black;
  --prompt-placeholder-color: #9ca3af;
  --prompt-border-radius: 0.375rem;
  --prompt-border-color: #d1d5db;
  --prompt-focus-border-color: #6366f1;

  --prompt-mention-pill-background-color: linear-gradient(
    135deg,
    #6366f1,
    #8b5cf6
  );
  --prompt-mention-pill-color: white;
  --prompt-mention-pill-border-radius: 9999px;

  --prompt-mention-menu-background-color: white;
  --prompt-mention-menu-border-color: #e5e7eb;
  --prompt-mention-menu-item-hover-color: #f3f4f6;
}

Advanced Usage

Multiple Triggers

Configure different triggers for different types of mentions:

<Prompt
  placeholder="Type @, #, or / ..."
  mentionConfigs={[
    { trigger: "@", options: peopleOptions },
    { trigger: "#", options: tagOptions },
    { trigger: "/", options: commandOptions, menuPosition: "above" },
  ]}
/>

Nested Menus

Create hierarchical option structures:

const options = [
  {
    id: "team",
    label: "Team Members",
    icon: <UsersIcon />,
    children: [
      { id: "alice", label: "Alice Johnson" },
      { id: "bob", label: "Bob Smith" },
    ],
  },
  {
    id: "projects",
    label: "Projects",
    icon: <FolderIcon />,
    children: [
      { id: "alpha", label: "Project Alpha" },
      { id: "beta", label: "Project Beta" },
    ],
  },
];

Navigate with:

  • Tab or β†’ β€” Enter submenu
  • Escape or ← β€” Exit submenu

Icons and Labels

Add icons and secondary labels to options:

const fileOptions = [
  {
    id: "prompt-tsx",
    label: "Prompt.tsx",
    labelRight: "src/components/",
    icon: <TypeScriptIcon />,
    indent: 1,
  },
];

Auto File Extension Icons

Automatically add file type icons based on file extensions:

<Prompt
  extensionIcons={true}
  mentionConfigs={[{ trigger: "@", options: fileOptions }]}
/>

Supports: .ts, .tsx, .js, .jsx, .css, .html, .json, .md, .py, .go, .rs, .sql, and many more.

Dividers and Titles

Organize options with visual separators:

const options = [
  { id: "title-people", label: "People", type: "title" },
  { id: "alice", label: "Alice" },
  { id: "bob", label: "Bob" },
  { id: "divider-1", label: "", type: "divider" },
  { id: "title-files", label: "Files", type: "title" },
  { id: "readme", label: "README.md" },
];

Programmatic Control (Ref)

Use the imperative handle to control the prompt externally:

import { useRef } from "react";
import { Prompt, PromptHandle, MentionOption } from "prompt-mentions";

function MyComponent() {
  const promptRef = useRef<PromptHandle>(null);

  const handleAddMention = (option: MentionOption) => {
    // Append mention with default trigger (@)
    promptRef.current?.appendMention(option);

    // Or with a specific trigger
    promptRef.current?.appendMention(option, "#");

    // Focus the input
    promptRef.current?.focus();
  };

  const handleInsertText = () => {
    // Insert text at current cursor position (or at end if not focused)
    // Behaves like typing - triggers mention menu when a trigger character is inserted
    promptRef.current?.insertText("Hello ");

    // Insert a trigger to open the mention menu
    promptRef.current?.insertText("@");
  };

  return (
    <>
      <Prompt
        ref={promptRef}
        mentionConfigs={[
          { trigger: "@", options: userOptions },
          { trigger: "#", options: tagOptions },
        ]}
      />
      <button onClick={() => handleAddMention({ id: "alice", label: "Alice" })}>
        Add @Alice
      </button>
      <button onClick={handleInsertText}>Insert Text</button>
    </>
  );
}

PromptHandle Methods

Method Signature Description
appendMention (option: MentionOption, trigger?: string) => void Appends a mention pill to the end of the input
focus () => void Focuses the prompt input
insertText (text: string) => void Inserts text at cursor position. Behaves like typingβ€”triggers mention menu when a trigger character is inserted

Initial Value with Mentions

Pre-populate the input with existing mentions:

<Prompt
  initialValue="Hello @[alice]! Please check @[main-ts]"
  mentionConfigs={[{ trigger: "@", options }]}
/>

The format is trigger[id] where id matches an option's id field.

Exports

// Components
export { Prompt, Message } from "prompt-mentions";

// Types
export type {
  MentionOption,
  MentionItemType,
  SelectedMention,
  PromptTheme,
  PresetThemeName,
} from "prompt-mentions";

// Theme utilities
export { themeToStyles, presetThemes, defaultTheme } from "prompt-mentions";

// Extension icon utilities
export {
  getExtensionIcon,
  extensionIconMap,
  filenameIconMap,
  DefaultFileIcon,
  DefaultFolderIcon,
} from "prompt-mentions";

Keyboard Shortcuts

Key Action
↑ / ↓ Navigate menu options
Enter Select highlighted option
Tab / β†’ Enter submenu (if available)
Escape / ← Exit submenu or close menu
Backspace Delete mention (when cursor is adjacent)

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Development

# Install dependencies
npm install

# Run Storybook for development
npm run storybook

# Run tests
npm run test

# Build the library
npm run build

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to the main repository.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT Β© (https://github.com/getnao/prompt-mentions/blob/main/LICENSE)


Made with ❀️ by nao Labs