Arkpad
FeaturesInteraction

Floating Menu

A contextual toolbar that appears on empty lines to suggest block insertions.

Type: Extension · Category: Interaction

The Floating Menu appears next to empty lines in the editor, offering quick access to insert headings, lists, tables, and other block-level elements without needing a toolbar.

Usage

In Arkpad, the floating menu is completely headless and built for zero-flicker performance. You configure it in your editor extensions, and then mount the <FloatingMenu> React wrapper component in your render tree:

import React from "react";
import { useArkpadEditor, ArkpadEditorContent, ArkpadProvider, FloatingMenu } from "@arkpad/react";
import { Engine } from "@arkpad/core";
import { Heading } from "@arkpad/extension-heading";
import { BulletList } from "@arkpad/extension-bullet-list";
import { FloatingMenu as FloatingMenuExtension } from "@arkpad/extension-floating-menu";

const extensions = [Engine, Heading, BulletList, FloatingMenuExtension];

export default function MyEditor() {
  const editor = useArkpadEditor({ extensions, content: "<p></p>" });

  return (
    <ArkpadProvider editor={editor}>
      <div className="editor-wrapper relative">
        {/* Mount the FloatingMenu component */}
        <FloatingMenu className="flex gap-1 p-1 bg-fd-popover border border-fd-border rounded-lg shadow-lg">
          <button
            onClick={() => editor.runCommand("toggleHeading", { level: 2 })}
            className="px-2 py-1 hover:bg-fd-accent rounded text-sm"
          >
            H2
          </button>
          <button
            onClick={() => editor.runCommand("toggleBulletList")}
            className="px-2 py-1 hover:bg-fd-accent rounded text-sm"
          >
            Bullet List
          </button>
        </FloatingMenu>

        <ArkpadEditorContent editor={editor} />
      </div>
    </ArkpadProvider>
  );
}

Demo

Installation

import { FloatingMenu } from "@arkpad/extension-floating-menu";

Configuration

Options

NameTypeDefaultDescription
shouldShowFunction({ editor, state }) => empty && isParagraph && isEmpty && editor.isFocused()Custom callback to conditionally determine when the floating menu should be rendered.

Custom Trigger Conditions

You can override the default visibility logic to show the menu in custom empty blocks or under different focus conditions:

FloatingMenu.configure({
  shouldShow: ({ editor, state }) => {
    const { $from, empty } = state.selection;

    // Only show inside empty paragraph blocks
    const isParagraph = $from.parent.type.name === "paragraph";
    const isEmpty = $from.parent.content.size === 0;

    return empty && isParagraph && isEmpty && editor.isFocused();
  },
});