Releases: yoopta-editor/Yoopta-Editor
v6.0.2
[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.isExpandedguard from the editor'sonKeyDownhandler 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, andupdatemulti-block loops ineditor.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-primaryto 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).
decoratenow resolves placeholder from the closest parent element instead of only the root element. (#592)
Changed
- Media resize defaults: Removed hardcoded
650px/550pxdefault sizes from image, embed, and video render components in shadcn theme. Max sizes now derive from actual editor container width viaResizeObserver, with no artificial limits. (#592)
Added
- Placeholder documentation: Added comprehensive Placeholders section to
docs/core/editor.mdxcovering editor-level, element-level, nested plugin, and CSS styling. Updateddocs/core/plugins.mdxwith extended placeholder field docs and cross-references. (#592)
v6.0.1
[6.0.1] - 2026-02-27
Fixed
- Email serialization: Fixed
getEmailto check for valid root elements and handle invalid input gracefully inserializeTextNodes. Refactored callout and list plugins to use centralized theme styles for consistent email output. (#575) - Media plugins max size: Removed hardcoded
maxWidth/maxHeightfrom embed, image, and video plugins. Default sizing now usesInfinityfor 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
deleteElementandupdateElementfunctions, 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 baseto prevent overriding user styles.variables.cssis no longer auto-imported — users who don't have their own shadcn variables can import it separately. (#574)
v6.0.0-beta.22
[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--filterfor selective dev mode. - Dev workflow:
yarn devstarts the dev server. Useyarn dev --filter=@yoopta/editorto watch specific packages — replaces the oldPACKAGES="..." yarn devworkaround. - Dev playground: Removed
packages/development/. Theweb/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
[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.withoutNormalizingwrapper and addedrequestAnimationFrameDOM selection re-sync infocusBlockto 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
focusBlockis called after upload to restore selection so the toolbar renders instantly. - Image/Video preview blob leak: Fixed stale closure bug in
useImagePreviewanduseVideoPreviewwhereclearPreview()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
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
[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()anduseUpdateElementProps<T>()helper hooks for accessing element context and updating properties. - Table plugin: Added
scrollableprop (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
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
moveUpandmoveDownmethods - now properly usesTransforms.moveNodesand 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,isReadystate guard, andFloatingPortalfor 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
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/onChangecontrolled pattern on the component; - UI: All UI (toolbar, slash menu, block actions, etc.) are children of
<YooptaEditor>and useuseYooptaEditor()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>;pluginsandmarksare required increateYooptaEditor({ plugins, marks })and must not be passed to<YooptaEditor>.valueis not a prop of<YooptaEditor>. Useeditor.setEditorValue(data)for initial/loaded content andonChangeto react to changes.- To read content:
editor.getEditorValue()(or use the value passed toonChange).
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,SelectionBoxcome from@yoopta/ui.- For drag-and-drop: wrap with
BlockDndContextand userenderBlockwithSortableBlock(and optionalDragHandle).
4. Deprecated / removed patterns
@yoopta/tools(e.g.ActionMenuTool,Toolbar,LinkTool): deprecated; use components from@yoopta/uiinstead.<YooptaEditor tools={[...]} />: no longer supported; use children as above.value/ controlled value on<YooptaEditor>: removed; usesetEditorValue+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): initialYooptaContentValue.readOnly(optional): boolean.id(optional): custom editor id.
YooptaEditor props
editor(required): instance fromcreateYooptaEditor.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 currentYooptaContentValue.editor.setEditorValue(value): sets content (e.g. after load).editor.applyTransforms([{ type: 'validate_block_paths' }]): optional aftersetEditorValueto normalize paths.- Events:
editor.on('change', fn),editor.off('change', fn), same forpath-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:
- Apply to all plugins —
applyTheme(plugins)returns plugins with theme-styled elements. Use:createYooptaEditor({ plugins: applyTheme(plugins), marks }). - 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). Oldweb/next-exampleremoved 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, noplugins/valueonYooptaEditor). - 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)
- Create editor with
createYooptaEditor({ plugins, marks })(and optionalvalue,readOnly). - Remove
plugins,marks, andvaluefrom<YooptaEditor>. - Set initial content with
editor.setEditorValue(data)inuseEffect(or passvalueintocreateYooptaEditor). - Keep
onChangeon<YooptaEditor>and use it (and/oreditor.getEditorValue()) for persistence. - Move toolbar, block menu, slash menu, block actions, etc. inside
<YooptaEditor>as children. - Replace any
@yoopta/toolsusage with@yoopta/uicomponents (FloatingToolbar, ActionMenuList, SlashCommandMenu, etc.). - Optional: Use
applyTheme(plugins)when using@yoopta/themes-shadcn. - Optional: Add
BlockDndContext,renderBlockwithSortableBlock, andSelectionBoxas needed.
Version
- Package versions: e.g.
6.0.0-beta.xfor core and related packages.
Full Changelog: v4.9.9...v6.0.0-beta.17
v4.9.9
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
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
- @afshawnlotfi made their first contribution in #503
Full Changelog: v4.9.7...v4.9.8