Skip to content

Releases: yoopta-editor/Yoopta-Editor

v6.0.2

16 Mar 12:46

Choose a tag to compare

[6.0.2] - 2026-03-16

Fixed

  • Marks in Table plugin: Fixed bold, italic, underline, and other marks not toggling inside table cells. Removed Range.isExpanded guard from the editor's onKeyDown handler so mark hotkeys work with both collapsed and expanded selections. (#592)
  • Multi-block mark undo: Applying marks (bold, italic, highlight, etc.) across multiple selected blocks now undoes in a single Cmd+Z step instead of block-by-block. Wrapped toggle, addMark, removeMark, and update multi-block loops in editor.batchOperations(). (#592)
  • Video/Embed inline toolbar not showing: Fixed inline toolbar not appearing for video and embed blocks. Replaced Rnd callback ref with a regular div ref (same pattern as image) so the floating toolbar reference is available on mount. (#592)
  • Resize handles visibility on dark content: Changed resize handle styling for image, video, and embed from bg-primary to white handles with border and drop shadow (bg-white border border-border shadow-[0_0_4px_rgba(0,0,0,0.3)]) for consistent visibility on any background. (#592)
  • Placeholder support for nested plugins: Fixed placeholders not showing in nested plugin elements (e.g., Steps). decorate now resolves placeholder from the closest parent element instead of only the root element. (#592)

Changed

  • Media resize defaults: Removed hardcoded 650px/550px default sizes from image, embed, and video render components in shadcn theme. Max sizes now derive from actual editor container width via ResizeObserver, with no artificial limits. (#592)

Added

  • Placeholder documentation: Added comprehensive Placeholders section to docs/core/editor.mdx covering editor-level, element-level, nested plugin, and CSS styling. Updated docs/core/plugins.mdx with extended placeholder field docs and cross-references. (#592)

v6.0.1

27 Feb 21:25

Choose a tag to compare

[6.0.1] - 2026-02-27

Fixed

  • Email serialization: Fixed getEmail to check for valid root elements and handle invalid input gracefully in serializeTextNodes. Refactored callout and list plugins to use centralized theme styles for consistent email output. (#575)
  • Media plugins max size: Removed hardcoded maxWidth/maxHeight from embed, image, and video plugins. Default sizing now uses Infinity for better responsiveness. (#584)

Added

  • Highlight color removal: Added a button to the HighlightColorPicker to remove/reset background or text color. (#582)
  • Element operation tests: Added comprehensive test suites for deleteElement and updateElement functions, covering selection, path, and custom matchers. (#581)
  • Placeholders: Implemented per-element placeholders via .extend() and global editor placeholder. Added placeholder CSS to shadcn theme. (#583)

Changed

  • Theme CSS variables: Removed --yoopta-shadcn-* prefix from CSS variables. Theme now reads standard shadcn variables (--card, --foreground, --border, etc.) directly. Removed @tailwind base to prevent overriding user styles. variables.css is no longer auto-imported — users who don't have their own shadcn variables can import it separately. (#574)

v6.0.0-beta.22

19 Feb 12:57

Choose a tag to compare

[6.0.0-beta.22] - 2026-02-19

Changed

  • Monorepo: Lerna → Turborepo + Yarn Berry: Migrated from Lerna + Yarn v1 to Turborepo + Yarn Berry (v4). workspace:* protocol now resolves local packages correctly (fixes broken symlinks with prerelease versions). Turborepo provides build caching and --filter for selective dev mode.
  • Dev workflow: yarn dev starts the dev server. Use yarn dev --filter=@yoopta/editor to watch specific packages — replaces the old PACKAGES="..." yarn dev workaround.
  • Dev playground: Removed packages/development/. The web/next-app-example/ app is now the development workspace.
  • Publishing: Lerna → Changesets: Versioning and publishing now uses Changesets with fixed version groups — all @yoopta/* packages share the same version.
  • React 19: Upgraded monorepo to React 19. Packages keep peerDependencies: "react": ">=18.2.0" for backwards compatibility.

Added

  • @yoopta/emoji: New plugin for emoji insertion (added in beta.21, first included in workspace build).

v6.0.0-beta.21

19 Feb 12:56

Choose a tag to compare

[6.0.0-beta.21] - 2026-02-17

Fixed

  • List plugins (Enter key): Fixed focus loss when pressing Enter in bulleted, numbered, and todo lists — cursor would become invisible and typing stopped working (especially in Safari). Removed unnecessary Editor.withoutNormalizing wrapper and added requestAnimationFrame DOM selection re-sync in focusBlock to recover from slate-react's layout effect clearing the selection.
  • Block focus on click: Fixed clicking on a block (e.g., third block) causing a brief focus jump to the first block. Moved editor.focus() call so it only fires when clicking outside any block, not when clicking on a specific block where the browser handles focus natively.
  • SelectionBox scroll: Added auto-scrolling when dragging selection near viewport edges. Selection origin is now tracked in document coordinates so the selection grows correctly as the page scrolls, selecting all blocks between the start position and the current mouse position.
  • Image inline toolbar after upload: Fixed image inline toolbar not appearing immediately after file upload. The file picker dialog steals browser focus and clears the Slate selection; now focusBlock is called after upload to restore selection so the toolbar renders instantly.
  • Image/Video preview blob leak: Fixed stale closure bug in useImagePreview and useVideoPreview where clearPreview() would fail to revoke the blob URL when called from async upload callbacks. Preview URL is now tracked via a ref to avoid stale state in closures.

v6.0.0-beta.20

12 Feb 12:51

Choose a tag to compare

Added

  • @yoopta/collaboration: New core package for real-time collaborative editing. Uses Yjs CRDT for conflict-free sync, with Slate ↔ Yjs binding, awareness (presence), remote cursors and selection, and WebSocket provider support. Hooks: useCollaboration, useConnectionStatus, useRemoteCursors. See docs/core/collaboration and the Collaboration example.

Full Changelog: v6.0.0-beta.19...v6.0.0-beta.20

v6.0.0-beta.19

06 Feb 21:53

Choose a tag to compare

[6.0.0-beta.19] - 2026-02-07

Added

  • ElementOptions (@yoopta/ui): New compound component for inline element configuration popovers. Includes Root, Trigger, Content, Group, Label, Separator, Select, Toggle, Slider, ColorPicker, and Input components. Built on Radix UI primitives.
  • ElementOptions hooks: Added useElementOptions() and useUpdateElementProps<T>() helper hooks for accessing element context and updating properties.
  • Table plugin: Added scrollable prop (default: true) - tables now respect column widths and scroll horizontally when wider than container.
  • Documentation: Added comprehensive ElementOptions documentation with API reference and examples.

Fixed

  • FloatingBlockActions: Fixed positioning when blocks have margin-top styles. Now finds [data-element-type] element and accounts for its margin offset.
  • Table controls: Fixed column controls, add row/column buttons appearing outside visible bounds when table is scrollable. Controls now stay within the visible scroll container area.
  • ElementOptions ColorPicker: Added debounced onChange (300ms) to prevent flooding undo/redo history, plus HexColorInput field and swatch preview.

Changed

  • ElementOptions: Migrated from floating-ui to Radix UI Popover for better accessibility and positioning.

Full Changelog: v6.0.0-beta.18...v6.0.0-beta.19

v6.0.0-beta.18

04 Feb 19:59

Choose a tag to compare

What's Changed

Fixed

  • FloatingBlockActions: Fixed hover detection - users can now reliably reach floating actions when moving cursor from block to actions. Uses JavaScript-based extended bounds checking instead of CSS pseudo-elements.
  • FloatingToolbar (Safari): Fixed button clicks immediately closing the toolbar in Safari by adding preventDefault() on mouseDown.
  • HighlightColorPicker: Fixed click-outside handling using FloatingOverlay approach for reliable behavior across browsers including Safari.
  • HighlightColorPicker: Added debounce (300ms) to color picker onChange to prevent flooding undo/redo history with every color change.
  • SelectionBox: Fixed native text selection appearing during programmatic block selection by preventing default and setting user-select: none.
  • Steps plugin: Fixed buggy moveUp and moveDown methods - now properly uses Transforms.moveNodes and recalculates order values.
  • Inline toolbars positioning (Safari): Fixed image, file, embed, and video inline toolbars appearing at top-left corner (0,0) in Safari. Now uses useLayoutEffect, isReady state guard, and FloatingPortal for proper positioning.
  • Image resize handlers: Added contrasting white ring (ring-2 ring-white/80) for visibility on dark images.
  • Image resize (left handle): Fixed buggy left-side resizing by anchoring position with position={{ x: 0, y: 0 }}.

Changed

  • Code/CodeGroup themes: Shiki theme colors now use scoped CSS variables on elements instead of global document variables for better isolation.

v6.0.0-beta.0

03 Feb 16:00

Choose a tag to compare

What's Changed

V6 Changes

Major version with significant API and architectural changes


Summary

  • Editor creation: Plugins, value and marks are passed to createYooptaEditor(), not to <YooptaEditor>.
  • Content: No value / onChange controlled pattern on the component;
  • UI: All UI (toolbar, slash menu, block actions, etc.) are children of <YooptaEditor> and use useYooptaEditor() from context.
  • Packages: Headless core, separate @yoopta/ui, themes (@yoopta/themes-shadcn), namespace APIs (Blocks, Elements, Marks, Selection).
  • Docs & examples: Documentation and examples updated for the new API.

Breaking changes

1. Editor creation and YooptaEditor props

Before (master / 4.9.x):

const editor = useMemo(() => createYooptaEditor(), []);

<YooptaEditor
  editor={editor}
  plugins={plugins}
  marks={marks}
  value={value}
  onChange={setValue}
  placeholder="..."
/>;

After (v6):

const editor = useMemo(() => createYooptaEditor({ plugins, marks, value: initialValue}), []);

<YooptaEditor
  editor={editor}
  onChange={(value) => {
    /* persist or setState */
  }}
  placeholder="Type / to open menu...">
  {/* UI components as children */}
</YooptaEditor>;
  • plugins and marks are required in createYooptaEditor({ plugins, marks }) and must not be passed to <YooptaEditor>.
  • value is not a prop of <YooptaEditor>. Use editor.setEditorValue(data) for initial/loaded content and onChange to react to changes.
  • To read content: editor.getEditorValue() (or use the value passed to onChange).

2. Optional initial value at creation

You can still pass initial content when creating the editor:

createYooptaEditor({ plugins, marks, value: initialContent, readOnly: false });

Or set it later in useEffect with editor.setEditorValue(initialContent).

3. UI components as children

Before (master): Tools or toolbar could be passed as props or a separate layer.

After (v6): All UI that needs the editor must be children of <YooptaEditor> so they can use useYooptaEditor():

<YooptaEditor editor={editor} onChange={onChange} placeholder="...">
  <FloatingToolbar />
  <FloatingBlockActions />
  <SlashCommandMenu />
  <SelectionBox selectionBoxElement={containerRef} />
</YooptaEditor>
  • FloatingToolbar, ActionMenuList, SlashCommandMenu, FloatingBlockActions, BlockOptions, SelectionBox come from @yoopta/ui.
  • For drag-and-drop: wrap with BlockDndContext and use renderBlock with SortableBlock (and optional DragHandle).

4. Deprecated / removed patterns

  • @yoopta/tools (e.g. ActionMenuTool, Toolbar, LinkTool): deprecated; use components from @yoopta/ui instead.
  • <YooptaEditor tools={[...]} />: no longer supported; use children as above.
  • value / controlled value on <YooptaEditor>: removed; use setEditorValue + onChange.

New or changed API

createYooptaEditor(options)

  • plugins (required): array of plugin instances.
  • marks (optional): array of mark types (e.g. Bold, Italic).
  • value (optional): initial YooptaContentValue.
  • readOnly (optional): boolean.
  • id (optional): custom editor id.

YooptaEditor props

  • editor (required): instance from createYooptaEditor.
  • onChange (optional): (value: YooptaContentValue, options: { operations }) => void.
  • onPathChange (optional): (path: YooptaPath) => void.
  • placeholder, autoFocus, className, style, renderBlock, children.

No plugins, marks, or value.

Editor instance

  • editor.getEditorValue(): returns current YooptaContentValue.
  • editor.setEditorValue(value): sets content (e.g. after load).
  • editor.applyTransforms([{ type: 'validate_block_paths' }]): optional after setEditorValue to normalize paths.
  • Events: editor.on('change', fn), editor.off('change', fn), same for path-change, etc.
  • Block operations: insertBlock, deleteBlock, updateBlock, toggleBlock, moveBlock, focusBlock, etc.
  • Elements: insertElement, updateElement, deleteElement, getElement, getElements, etc.
  • Parsers: getHTML, getMarkdown, getPlainText, getEmail (each can take value or use current).
  • History: undo, redo, batchOperations.

Namespace APIs (optional usage)

From @yoopta/editor you can use:

  • Blocks.*: Blocks.insertBlock(editor, ...), Blocks.deleteBlock(editor, ...), etc.
  • Elements.*: Elements.insertElement(editor, ...), etc.
  • Marks.*: Marks.toggle(editor, { type: 'bold' }), etc.
  • Selection.*: selection helpers.

These mirror methods on the editor instance.


UI package (@yoopta/ui)

  • FloatingToolbar — formatting toolbar (compound: Content, Group, Button, Separator).
  • ActionMenuList — “Turn into” / block type menu (controlled: open, onOpenChange, anchor).
  • SlashCommandMenu — slash “/” command menu (compound: Content, List, Item, Empty, Footer).
  • FloatingBlockActions — hover actions per block (render props with blockId).
  • BlockOptions — block context menu (Duplicate, Delete, Turn into, etc.).
  • SelectionBox — rectangle selection for multiple blocks (selectionBoxElement = container ref).
  • BlockDndContext, SortableBlock, DragHandle — drag-and-drop reorder.

All of these are used as children of <YooptaEditor> and rely on useYooptaEditor().


Themes

The editor and plugins are headless by default. Theme packages provide optional UI for plugin elements. Available: @yoopta/themes-shadcn (production), @yoopta/themes-material (in progress).

Two ways to use theme UI:

  1. Apply to all pluginsapplyTheme(plugins) returns plugins with theme-styled elements. Use: createYooptaEditor({ plugins: applyTheme(plugins), marks }).
  2. Apply to a single plugin — import the theme UI for that plugin and extend: e.g. import { CalloutUI } from '@yoopta/themes-shadcn/callout'; Callout.extend({ elements: CalloutUI }).

CSS is applied by the theme package; no need to pass plugins/marks to <YooptaEditor>.


Package and repo structure

  • Core: @yoopta/editor (headless), @yoopta/ui (UI components), @yoopta/exports (serializers).
  • Plugins: e.g. @yoopta/paragraph, @yoopta/headings, @yoopta/code, @yoopta/table, etc.
  • Marks: @yoopta/marks (Bold, Italic, Underline, etc.).
  • Themes: @yoopta/themes-shadcn, @yoopta/themes-material (in development).
  • Examples: web/next-app-example, web/vite-example, packages/development (playground). Old web/next-example removed or replaced.

Yoopta Documentation

  • Getting started, quickstart, installation, introduction: Updated to v6 API (createYooptaEditor({ plugins, marks }), setEditorValue, onChange, UI as children).
  • UI overview and per-component docs (docs/ui/*.mdx): Updated to SlashCommandMenu, compound components, and correct usage (children, no plugins/value on YooptaEditor).
  • Mintlify docs: Plugin previews and plugin playground (iframe) snippets; accordion and other plugin docs aligned with v6.

Migration checklist (from 4.9.x to v6)

  1. Create editor with createYooptaEditor({ plugins, marks }) (and optional value, readOnly).
  2. Remove plugins, marks, and value from <YooptaEditor>.
  3. Set initial content with editor.setEditorValue(data) in useEffect (or pass value into createYooptaEditor).
  4. Keep onChange on <YooptaEditor> and use it (and/or editor.getEditorValue()) for persistence.
  5. Move toolbar, block menu, slash menu, block actions, etc. inside <YooptaEditor> as children.
  6. Replace any @yoopta/tools usage with @yoopta/ui components (FloatingToolbar, ActionMenuList, SlashCommandMenu, etc.).
  7. Optional: Use applyTheme(plugins) when using @yoopta/themes-shadcn.
  8. Optional: Add BlockDndContext, renderBlock with SortableBlock, and SelectionBox as needed.

Version

  • Package versions: e.g. 6.0.0-beta.x for core and related packages.

Full Changelog: v4.9.9...v6.0.0-beta.17

v4.9.9

11 Jun 17:59

Choose a tag to compare

What's Changed

  • Fix issue where content is lost when pasting HTML containing marks or lists by @Darginec05 in #515
  • Delete unneccessary div in block render by @Darginec05 in #517
  • More validations via slate extension for each plugin by @Darginec05 in #518

Full Changelog: v4.9.8...v4.9.9

v4.9.8

27 May 22:27

Choose a tag to compare

What's Changed

  • fix(editor): Fixed events for multiple editors by making them not global by @afshawnlotfi in #503
  • Added classname to image when it's zoomed by @Darginec05 in #510

New Contributors

Full Changelog: v4.9.7...v4.9.8