AI Menu

Available in Start plan

A fully-featured AI-powered contextual menu for Tiptap editors. Provides intelligent content editing, generation, and transformation capabilities with floating menu positioning and customizable AI actions.

Installation

Add the component via the Tiptap CLI:

npx @tiptap/cli@latest add ai-menu

Components

<AiMenu />

A comprehensive AI-powered menu that provides contextual editing and generation capabilities.

Usage

import { EditorContent, EditorContext, useEditor } from '@tiptap/react'  // --- Tiptap Core Extensions --- import { StarterKit } from '@tiptap/starter-kit' import { Ai } from '@tiptap-pro/extension-ai' import { UiState } from '@/components/tiptap-extension/ui-state-extension'  import { HorizontalRule } from '@/components/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension' import { Selection } from '@tiptap/extensions' import { AiProvider, useAi } from '@/components/contexts/ai-context'  // --- Tiptap UI --- import { AiMenu } from '@/components/tiptap-ui/ai-menu' import { AiAskButton } from '@/components/tiptap-ui/ai-ask-button'  // --- UI Primitive --- import { ButtonGroup } from '@/components/tiptap-ui-primitive/button'  // --- Utils --- import { TIPTAP_AI_APP_ID } from '@/lib/tiptap-collab-utils'  // --- Tiptap Node --- import '@/components/tiptap-node/blockquote-node/blockquote-node.scss' import '@/components/tiptap-node/code-block-node/code-block-node.scss' import '@/components/tiptap-node/horizontal-rule-node/horizontal-rule-node.scss' import '@/components/tiptap-node/heading-node/heading-node.scss' import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'  export const AiMenuExample = () => {  return (  <AiProvider>  <AiEditorWrapper />  </AiProvider>  ) }  const AiEditorWrapper = () => {  const { aiToken } = useAi()   if (!aiToken) {  return <div className="tiptap-editor-wrapper">Loading AI...</div>  }   return <AiEditor aiToken={aiToken} /> }  const AiEditor = ({ aiToken }: { aiToken: string }) => {  const editor = useEditor({  immediatelyRender: false,  extensions: [  StarterKit.configure({  horizontalRule: false,  }),  HorizontalRule,  Selection,  UiState,  Ai.configure({  appId: TIPTAP_AI_APP_ID,  token: aiToken,  autocompletion: false,  showDecorations: true,  hideDecorationsOnStreamEnd: false,  onLoading: (context) => {  context.editor.commands.aiGenerationSetIsLoading(true)  context.editor.commands.aiGenerationHasMessage(false)  },  onChunk: (context) => {  context.editor.commands.aiGenerationSetIsLoading(true)  context.editor.commands.aiGenerationHasMessage(true)  },  onSuccess: (context) => {  const hasMessage = !!context.response  context.editor.commands.aiGenerationSetIsLoading(false)  context.editor.commands.aiGenerationHasMessage(hasMessage)  },  }),  ],  content: ` <p>Today, we're exploring how AI is transforming creative workflows. From writing assistance to intelligent summarization, the tools at our fingertips are evolving fast. But how do we use them responsibly?</p> <p>In this article, we’ll look at real-world examples of AI enhancing—not replacing—human creativity.</p>  `,  })   return (  <EditorContext.Provider value={{ editor }}>  <div className="controls-bar">  <div className="control-item">  <ButtonGroup orientation="horizontal">  <AiAskButton />  </ButtonGroup>  </div>  </div>   <EditorContent editor={editor} role="presentation" className="control-showcase">  <AiMenu />  </EditorContent>  </EditorContext.Provider>  ) }

Props

NameTypeDefaultDescription
editorEditor | nullundefinedThe Tiptap editor instance

<AiMenuStateProvider />

State provider that manages AI menu state across the application.

Usage

import { AiMenuStateProvider } from '@/components/tiptap-ui/ai-menu'  function App() {  return <AiMenuStateProvider>{/* Your editor components */}</AiMenuStateProvider> }

<AiMenuContent />

The main content component that renders the AI menu interface.

Props

NameTypeDefaultDescription
editorEditor | nullundefinedThe Tiptap editor instance

Hooks

useAiMenuState()

Hook to access and manage AI menu state.

Usage

import { useAiMenuState } from '@/components/tiptap-ui/ai-menu'  function MyComponent() {  const { state, updateState, setFallbackAnchor, reset } = useAiMenuState()   const handleOpenMenu = () => {  updateState({ isOpen: true, shouldShowInput: true })  }   const handleCloseMenu = () => {  reset()  }   return (  <button onClick={state.isOpen ? handleCloseMenu : handleOpenMenu}>  {state.isOpen ? 'Close AI Menu' : 'Open AI Menu'}  </button>  ) }

Return Values

NameTypeDescription
stateAiMenuStateCurrent AI menu state
updateState(updates: Partial<AiMenuState>) => voidFunction to update menu state
setFallbackAnchor(element: HTMLElement | null, rect?) => voidSet fallback positioning anchor
reset() => voidReset menu state to initial state

useAiContentTracker()

Hook to track AI-generated content changes in the editor.

Usage

import { useAiContentTracker } from '@/components/tiptap-ui/ai-menu'  function MyComponent() {  const { editor } = useTiptapEditor()   useAiContentTracker(editor, {  onContentChange: (hasAiContent) => {  console.log('AI content detected:', hasAiContent)  },  })   return <div>Component with AI content tracking</div> }

useTextSelectionTracker()

Hook to track text selection changes for menu positioning.

Usage

import { useTextSelectionTracker } from '@/components/tiptap-ui/ai-menu'  function MyComponent() {  const { editor } = useTiptapEditor()   useTextSelectionTracker(editor, {  onSelectionChange: (selection) => {  console.log('Selection changed:', selection)  },  })   return <div>Component with selection tracking</div> }

Sub-Components

<AiMenuItems />

Component that renders the available AI actions grouped by category.

Usage

import { AiMenuItems } from '@/components/tiptap-ui/ai-menu'  function CustomAiMenu() {  const { editor } = useTiptapEditor()   return (  <AiMenuItems  editor={editor}  availableActions={['improveWriting', 'aiFixSpellingAndGrammar', 'summarize']}  />  ) }

<AiMenuActions />

Component that renders action buttons for the AI menu (Accept, Regenerate, etc.).

Usage

import { AiMenuActions } from '@/components/tiptap-ui/ai-menu'  function CustomAiMenu() {  const { editor } = useTiptapEditor()   return (  <AiMenuActions  editor={editor}  onAccept={() => console.log('AI content accepted')}  onRegenerate={() => console.log('Regenerating AI content')}  />  ) }

<AiMenuInputTextarea />

Input component for custom AI prompts.

Usage

import { AiMenuInputTextarea } from '@/components/tiptap-ui/ai-menu'  function CustomPromptInput() {  const handleSubmit = (prompt: string) => {  console.log('User prompt:', prompt)  }   return (  <AiMenuInputTextarea  onSubmit={handleSubmit}  placeholder="Ask AI to help with your content..."  />  ) }

Utilities

getContextAndInsertAt(editor)

Utility function to determine the context and insertion point for AI operations.

import { getContextAndInsertAt } from '@/components/tiptap-ui/ai-menu'  const { context, insertAt, isSelection } = getContextAndInsertAt(editor)  if (isSelection) {  // Handle selection-based AI operation  editor.chain().aiEdit({ prompt: 'Improve this text', insertAt }).run() } else {  // Handle insertion-based AI operation  editor.chain().aiGenerate({ prompt: 'Write about AI', insertAt }).run() }

findPrioritizedAIElement(editor)

Finds the most appropriate DOM element for AI menu positioning.

import { findPrioritizedAIElement } from '@/components/tiptap-ui/ai-menu'  const targetElement = findPrioritizedAIElement(editor) if (targetElement) {  // Position menu relative to this element }

AI Actions

The AI Menu provides several built-in actions organized by category:

Edit Actions

  • Adjust Tone: Change the tone of selected text
  • Fix Spelling & Grammar: Correct spelling and grammar errors
  • Extend: Expand on the selected content
  • Shorten: Make the content more concise
  • Simplify Language: Use simpler, clearer language
  • Improve Writing: Enhance overall writing quality
  • Emojify: Add relevant emojis to the content

Write Actions

  • Continue Writing: Generate continuation of the content
  • Summarize: Create a summary of the selected text
  • Translate To: Translate content to different languages

State Management

AiMenuState Interface

interface AiMenuState {  isOpen: boolean  tone?: string  language: string  shouldShowInput: boolean  inputIsFocused: boolean  fallbackAnchor: {  element: HTMLElement | null  rect: DOMRect | null  } }

State Updates

The AI menu state can be updated using the updateState function:

const { updateState } = useAiMenuState()  // Open menu with input focused updateState({  isOpen: true,  shouldShowInput: true,  inputIsFocused: true, })  // Set language for translation updateState({ language: 'es' })  // Set tone for content adjustment updateState({ tone: 'professional' })

Requirements

Dependencies

  • @tiptap/react - Core Tiptap React integration
  • @tiptap-pro/extension-ai - AI extension for content generation
  • @tiptap/starter-kit - Basic Tiptap extensions
  • react-hotkeys-hook - Keyboard shortcut management

Extensions

  • ui-state-extension - Manages UI state for AI operations
  • selection-extension - Enhanced text selection handling

Referenced Components

  • use-tiptap-editor (hook)
  • use-ui-editor-state (hook)
  • menu (primitive)
  • button, button-group (primitive)
  • card (primitive)
  • combobox (primitive)
  • tiptap-utils (lib)
  • sparkles-icon, stop-circle-2-icon (icons)

Configuration

AI Provider Setup

import { AiProvider } from '@/contexts/ai-context'  function App() {  return (  <AiProvider appId="your-app-id" token="your-ai-token">  <YourEditor />  </AiProvider>  ) }