Skip to main content

Overview

The Full Setup example showcases Yoopta Editor with every major feature enabled. This is the most comprehensive example, demonstrating a Notion-like editing experience.

Live Demo

Try the interactive demo with all features enabled

Features Included

  • Floating Toolbar - Text formatting on selection
  • Slash Command Menu - Type / to insert blocks
  • Block Actions - Hover menu with drag handle
  • Selection Box - Multi-block selection
  • Drag & Drop - Reorder blocks with nested depth
  • Paragraph, Headings (H1-H3)
  • Bulleted, Numbered, and Todo Lists
  • Code blocks with syntax highlighting
  • Blockquotes and Callouts
  • Images, Videos, Files
  • Tables and Dividers
  • Accordion, Tabs, Steps
  • Embeds (YouTube, Figma, etc.)
  • Carousel and Table of Contents
  • Bold (Cmd/Ctrl + B)
  • Italic (Cmd/Ctrl + I)
  • Underline (Cmd/Ctrl + U)
  • Strikethrough (Cmd/Ctrl + Shift + S)
  • Code (Cmd/Ctrl + E)
  • Highlight with colors
  • @Mentions with dropdown
  • Emoji picker
  • Keyboard shortcuts
  • Undo/Redo history
  • Block nesting and indentation

Implementation

Basic Setup

import { useMemo, useCallback } from 'react';
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import { SelectionBox } from '@yoopta/ui/selection-box';
import { BlockDndContext, SortableBlock } from '@yoopta/ui/block-dnd';
import { applyTheme } from '@yoopta/themes-shadcn';
import { withMentions } from '@yoopta/mention';
import { withEmoji } from '@yoopta/emoji';

import { YooptaToolbar } from './components/yoopta-toolbar';
import { YooptaSlashCommandMenu } from './components/yoopta-slash-command-menu';
import { YooptaFloatingBlockActions } from './components/yoopta-floating-block-actions';
import { PLUGINS, MARKS } from './config';

function FullSetupEditor() {
  const editor = useMemo(() => {
    return withEmoji(
      withMentions(
        createYooptaEditor({
          plugins: applyTheme(PLUGINS),
          marks: MARKS,
        })
      )
    );
  }, []);

  const renderBlock = useCallback(({ children, blockId }) => {
    return <SortableBlock id={blockId} useDragHandle>{children}</SortableBlock>;
  }, []);

  return (
    <BlockDndContext editor={editor}>
      <YooptaEditor
        editor={editor}
        renderBlock={renderBlock}
        placeholder="Type / to open menu, or start typing..."
      >
        <YooptaToolbar />
        <YooptaFloatingBlockActions />
        <YooptaSlashCommandMenu />
        <SelectionBox />
      </YooptaEditor>
    </BlockDndContext>
  );
}

Plugin Configuration

import Paragraph from '@yoopta/paragraph';
import Headings from '@yoopta/headings';
import Lists from '@yoopta/lists';
import Blockquote from '@yoopta/blockquote';
import Code from '@yoopta/code';
import Callout from '@yoopta/callout';
import Image from '@yoopta/image';
import Video from '@yoopta/video';
import File from '@yoopta/file';
import Embed from '@yoopta/embed';
import Table from '@yoopta/table';
import Divider from '@yoopta/divider';
import Accordion from '@yoopta/accordion';
import Tabs from '@yoopta/tabs';
import Steps from '@yoopta/steps';
import Link from '@yoopta/link';
import Mention from '@yoopta/mention';
import Carousel from '@yoopta/carousel';
import TableOfContents from '@yoopta/table-of-contents';

export const PLUGINS = [
  Paragraph,
  Headings.HeadingOne,
  Headings.HeadingTwo,
  Headings.HeadingThree,
  Lists.BulletedList,
  Lists.NumberedList,
  Lists.TodoList,
  Blockquote,
  Code,
  Callout,
  Image.extend({
    options: {
      async onUpload(file) {
        // Your upload logic
        const url = await uploadImage(file);
        return { src: url };
      },
    },
  }),
  Video,
  File,
  Embed,
  Table,
  Divider,
  Accordion,
  Tabs,
  Steps,
  Link,
  Mention,
  Carousel,
  TableOfContents,
];

Marks Configuration

import { Bold, Italic, Underline, Strike, CodeMark, Highlight } from '@yoopta/marks';

export const MARKS = [Bold, Italic, Underline, Strike, CodeMark, Highlight];

UI Components

Floating Toolbar

The toolbar appears when text is selected:
import { FloatingToolbar } from '@yoopta/ui';
import { useYooptaEditor, Marks } from '@yoopta/editor';

function YooptaToolbar() {
  const editor = useYooptaEditor();

  return (
    <FloatingToolbar>
      <FloatingToolbar.Content>
        <FloatingToolbar.Group>
          <FloatingToolbar.Button
            onClick={() => Marks.toggle(editor, { type: 'bold' })}
            active={Marks.isActive(editor, { type: 'bold' })}
          >
            B
          </FloatingToolbar.Button>
          {/* More formatting buttons */}
        </FloatingToolbar.Group>
      </FloatingToolbar.Content>
    </FloatingToolbar>
  );
}

Slash Command Menu

Type / to open the block insertion menu:
import { SlashCommandMenu } from '@yoopta/ui';

function YooptaSlashCommandMenu() {
  return <SlashCommandMenu />;
}

Block Actions

Hover actions with drag handle and block options:
import { FloatingBlockActions, BlockOptions } from '@yoopta/ui';
import { useYooptaEditor, Blocks } from '@yoopta/editor';

function YooptaFloatingBlockActions() {
  const editor = useYooptaEditor();
  const [blockOptionsOpen, setBlockOptionsOpen] = useState(false);

  return (
    <FloatingBlockActions frozen={blockOptionsOpen}>
      {({ blockId }) => (
        <>
          <FloatingBlockActions.Button
            onClick={() => {
              const block = Blocks.getBlock(editor, { id: blockId });
              editor.insertBlock('Paragraph', { at: block.meta.order + 1 });
            }}
          >
            +
          </FloatingBlockActions.Button>
          <FloatingBlockActions.DragHandle />
          <BlockOptions
            open={blockOptionsOpen}
            onOpenChange={setBlockOptionsOpen}
          >
            {/* Block options menu */}
          </BlockOptions>
        </>
      )}
    </FloatingBlockActions>
  );
}

Drag and Drop

Enable block reordering with nested depth support:
import { BlockDndContext, SortableBlock } from '@yoopta/ui/block-dnd';

function Editor() {
  const renderBlock = useCallback(({ children, blockId }) => {
    return (
      <SortableBlock id={blockId} useDragHandle>
        {children}
      </SortableBlock>
    );
  }, []);

  return (
    <BlockDndContext editor={editor}>
      <YooptaEditor editor={editor} renderBlock={renderBlock}>
        {/* UI components */}
      </YooptaEditor>
    </BlockDndContext>
  );
}

Mentions and Emoji

Setup Mentions

import { withMentions } from '@yoopta/mention';
import Mention from '@yoopta/mention';
import { MentionDropdown } from '@yoopta/themes-shadcn/mention';

const editor = withMentions(
  createYooptaEditor({
    plugins: [...PLUGINS, Mention],
    marks: MARKS,
  })
);

// Add dropdown to editor
<YooptaEditor editor={editor}>
  <MentionDropdown />
  {/* Other components */}
</YooptaEditor>

Setup Emoji

import { withEmoji } from '@yoopta/emoji';
import { EmojiDropdown } from '@yoopta/themes-shadcn/emoji';

const editor = withEmoji(
  createYooptaEditor({ plugins: PLUGINS, marks: MARKS })
);

<YooptaEditor editor={editor}>
  <EmojiDropdown />
  {/* Other components */}
</YooptaEditor>

Source Code

View Full Source

Complete implementation on GitHub

Key Takeaways

1

Start with createYooptaEditor

Configure plugins and marks in the editor instance
2

Apply theme for styled UI

Use applyTheme() from @yoopta/themes-shadcn for pre-built block styling
3

Add UI components as children

All UI components (toolbar, menu, actions) must be children of <YooptaEditor>
4

Enable features with HOCs

Use withMentions() and withEmoji() to add special features
5

Implement drag & drop

Wrap with BlockDndContext and use SortableBlock in renderBlock

Next Steps

CMS Builder

See how to build a visual page builder

API Reference

Explore the complete API

Build docs developers (and LLMs) love