Skip to main content

Overview

The useYooptaReadOnly hook returns a boolean indicating whether the editor is currently in read-only mode. When read-only is enabled, users cannot edit content but can still read and select text.

Usage

import { useYooptaReadOnly } from '@yoopta/editor';

function EditorToolbar() {
  const isReadOnly = useYooptaReadOnly();

  return (
    <div className="toolbar">
      {!isReadOnly && <button>Edit</button>}
      {!isReadOnly && <button>Format</button>}
      <button>Copy</button>
    </div>
  );
}

Signature

function useYooptaReadOnly(): boolean

Returns

boolean - true if the editor is in read-only mode, false otherwise

Examples

Conditional Toolbar Rendering

function FloatingToolbar() {
  const isReadOnly = useYooptaReadOnly();

  if (isReadOnly) {
    return (
      <div className="read-only-toolbar">
        <button>Copy</button>
        <button>Share</button>
        <button>Export</button>
      </div>
    );
  }

  return (
    <div className="edit-toolbar">
      <button>Bold</button>
      <button>Italic</button>
      <button>Insert</button>
      <button>Delete</button>
    </div>
  );
}

Read-Only Indicator

function EditorHeader() {
  const isReadOnly = useYooptaReadOnly();

  return (
    <div className="editor-header">
      <h1>Document Editor</h1>
      {isReadOnly && (
        <span className="badge badge-warning">
          🔒 Read-only mode
        </span>
      )}
    </div>
  );
}

Disable Edit Actions

function BlockActions({ blockId }: { blockId: string }) {
  const isReadOnly = useYooptaReadOnly();
  const editor = useYooptaEditor();

  const handleDelete = () => {
    if (isReadOnly) return;
    editor.deleteBlock({ blockId });
  };

  const handleEdit = () => {
    if (isReadOnly) return;
    editor.focusBlock({ blockId });
  };

  return (
    <div>
      <button onClick={handleEdit} disabled={isReadOnly}>
        Edit
      </button>
      <button onClick={handleDelete} disabled={isReadOnly}>
        Delete
      </button>
    </div>
  );
}

Conditional Styling

function EditorContainer() {
  const isReadOnly = useYooptaReadOnly();

  return (
    <div
      className="editor-container"
      style={{
        backgroundColor: isReadOnly ? '#f5f5f5' : '#ffffff',
        cursor: isReadOnly ? 'default' : 'text',
        userSelect: isReadOnly ? 'text' : 'auto',
      }}
    >
      <YooptaEditor {...props} />
    </div>
  );
}

Export-Only Mode

function EditorWithExport() {
  const isReadOnly = useYooptaReadOnly();
  const editor = useYooptaEditor();

  const handleExport = () => {
    const html = editor.getHTML(editor.children);
    const blob = new Blob([html], { type: 'text/html' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'document.html';
    a.click();
  };

  return (
    <div>
      <YooptaEditor {...props} />
      {isReadOnly && (
        <div className="export-panel">
          <p>Viewing in read-only mode</p>
          <button onClick={handleExport}>Export Document</button>
        </div>
      )}
    </div>
  );
}

Toggle Read-Only Mode

function EditorWithToggle() {
  const [readOnly, setReadOnly] = useState(false);
  const editor = useMemo(
    () => createYooptaEditor({ plugins: PLUGINS }),
    []
  );

  // Update editor's readOnly property
  useEffect(() => {
    editor.readOnly = readOnly;
  }, [readOnly, editor]);

  return (
    <div>
      <button onClick={() => setReadOnly(!readOnly)}>
        {readOnly ? 'Enable Editing' : 'Disable Editing'}
      </button>
      <YooptaEditor editor={editor} readOnly={readOnly} />
    </div>
  );
}

function EditorStatus() {
  const isReadOnly = useYooptaReadOnly();

  return (
    <div>
      Mode: {isReadOnly ? 'Read-only' : 'Editable'}
    </div>
  );
}

Permission-Based Editing

function DocumentEditor({ userPermissions }) {
  const canEdit = userPermissions.includes('edit');
  const editor = useMemo(
    () => createYooptaEditor({ plugins: PLUGINS }),
    []
  );

  return (
    <div>
      <PermissionBanner />
      <YooptaEditor editor={editor} readOnly={!canEdit} />
    </div>
  );
}

function PermissionBanner() {
  const isReadOnly = useYooptaReadOnly();

  if (!isReadOnly) return null;

  return (
    <div className="banner banner-info">
      You don't have permission to edit this document.
    </div>
  );
}

Keyboard Shortcut Protection

function KeyboardHandler() {
  const isReadOnly = useYooptaReadOnly();
  const editor = useYooptaEditor();

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Prevent edit shortcuts in read-only mode
      if (isReadOnly) {
        if (e.metaKey || e.ctrlKey) {
          const preventKeys = ['b', 'i', 'u', 'k', 'z', 'y'];
          if (preventKeys.includes(e.key.toLowerCase())) {
            e.preventDefault();
            return;
          }
        }
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [isReadOnly]);

  return null;
}

Use Cases

  • View Mode: Display content without allowing edits
  • Permission Controls: Restrict editing based on user permissions
  • Review Mode: Allow stakeholders to review content without changes
  • Published Content: Show finalized documents in read-only mode
  • Conditional UI: Show/hide editing tools based on mode
  • Export Views: Provide read-only view with export options
  • Archived Content: Display historical content that shouldn’t be modified

Setting Read-Only Mode

The read-only state is set on the editor instance and passed as a prop to YooptaEditor:
function App() {
  const editor = useMemo(
    () => createYooptaEditor({ plugins: PLUGINS }),
    []
  );

  return (
    <YooptaEditor 
      editor={editor} 
      readOnly={true}  // Set read-only mode
    />
  );
}

Implementation Details

Under the hood, this hook accesses the readOnly property from the editor instance:
// Simplified implementation
const useYooptaReadOnly = () => useYooptaEditor().readOnly;

See Also

Build docs developers (and LLMs) love