Skip to main content

Excalidraw Component

The Excalidraw component is the main React component that renders the complete Excalidraw editor. It provides a fully-featured, customizable whiteboard experience that can be embedded in any React application.

Basic Usage

import { Excalidraw } from "@excalidraw/excalidraw";

function App() {
  return (
    <div style={{ height: "100vh" }}>
      <Excalidraw />
    </div>
  );
}

Props

Core Props

onChange
function
Callback fired when elements, appState, or files change.
onChange?: (
  elements: readonly ExcalidrawElement[],
  appState: AppState,
  files: BinaryFiles,
) => void;
initialData
object | function
Initial scene data to load. Can be an object or a function that returns initial data (sync or async).
initialData?: 
  | ExcalidrawInitialDataState 
  | (() => Promise<ExcalidrawInitialDataState | null>)
  | Promise<ExcalidrawInitialDataState | null>;
excalidrawAPI
function
Callback to receive the Excalidraw API instance for imperative actions.
excalidrawAPI?: (api: ExcalidrawImperativeAPI) => void;

Appearance Props

theme
'light' | 'dark'
Sets the editor theme. When not provided, users can toggle between themes.
viewModeEnabled
boolean
default:"false"
When true, renders the editor in view-only mode with no editing capabilities.
zenModeEnabled
boolean
default:"false"
When true, hides the UI chrome for a distraction-free experience.
gridModeEnabled
boolean
default:"false"
When true, shows a grid on the canvas.
name
string
Name of the document/scene, used as the default filename when exporting.

Behavior Props

autoFocus
boolean
default:"false"
When true, automatically focuses the canvas on mount.
detectScroll
boolean
default:"true"
When true, detects scrolling outside the canvas to prevent accidental scrolls.
handleKeyboardGlobally
boolean
default:"false"
When true, keyboard shortcuts work globally instead of only when canvas is focused.
renderScrollbars
boolean
Controls whether to render scrollbars on the canvas.

Collaboration Props

isCollaborating
boolean
default:"false"
Indicates whether the editor is in collaboration mode.
onPointerUpdate
function
Callback fired when the user’s pointer position changes, useful for real-time collaboration.
onPointerUpdate?: (payload: {
  pointer: { x: number; y: number; tool: "pointer" | "laser" };
  button: "down" | "up";
  pointersMap: Map<number, Gesture["pointers"]>;
}) => void;

Event Callbacks

onIncrement
function
Called on every state increment (ephemeral or durable).
onIncrement?: (event: DurableIncrement | EphemeralIncrement) => void;
onPaste
function
Called when paste is triggered. Return true to prevent default paste behavior.
onPaste?: (
  data: ClipboardData,
  event: ClipboardEvent | null,
) => Promise<boolean> | boolean;
onDuplicate
function
Called when elements are duplicated. Return modified elements or void.
onDuplicate?: (
  nextElements: readonly ExcalidrawElement[],
  prevElements: readonly ExcalidrawElement[],
) => ExcalidrawElement[] | void;
onPointerDown
function
Called on pointer down events.
onPointerDown?: (
  activeTool: AppState["activeTool"],
  pointerDownState: PointerDownState,
) => void;
onPointerUp
function
Called on pointer up events.
onPointerUp?: (
  activeTool: AppState["activeTool"],
  pointerDownState: PointerDownState,
) => void;
onScrollChange
function
Called when the canvas scroll position or zoom changes.
onScrollChange?: (scrollX: number, scrollY: number, zoom: Zoom) => void;
onUserFollow
function
Called when following a collaborator.
onUserFollow?: (payload: OnUserFollowedPayload) => void;

Library & File Management

onLibraryChange
function
Called when the library items change.
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
generateIdForFile
function
Custom function to generate IDs for uploaded files.
generateIdForFile?: (file: File) => string | Promise<string>;
libraryReturnUrl
string
URL to return to after opening the public library.
Called when a link is clicked.
onLinkOpen?: (
  element: NonDeletedExcalidrawElement,
  event: CustomEvent<{ nativeEvent: MouseEvent | React.PointerEvent }>,
) => void;
Generate a custom link for selected element(s).
generateLinkForSelection?: (id: string, type: "element" | "group") => string;

Embedding

validateEmbeddable
boolean | string[] | RegExp | RegExp[] | function
Controls which URLs can be embedded. Can be a boolean, array of allowed domains, regex pattern(s), or validation function.
validateEmbeddable?: 
  | boolean 
  | string[] 
  | RegExp 
  | RegExp[] 
  | ((link: string) => boolean | undefined);
renderEmbeddable
function
Custom renderer for embeddable elements.
renderEmbeddable?: (
  element: NonDeleted<ExcalidrawEmbeddableElement>,
  appState: AppState,
) => JSX.Element | null;

Custom UI Rendering

renderTopLeftUI
function
Render custom UI in the top-left corner.
renderTopLeftUI?: (
  isMobile: boolean,
  appState: UIAppState,
) => JSX.Element | null;
renderTopRightUI
function
Render custom UI in the top-right corner.
renderTopRightUI?: (
  isMobile: boolean,
  appState: UIAppState,
) => JSX.Element | null;
renderCustomStats
function
Render custom statistics panel content.
renderCustomStats?: (
  elements: readonly NonDeletedExcalidrawElement[],
  appState: UIAppState,
) => JSX.Element;

UI Configuration

UIOptions
object
Configure which UI elements are displayed and their behavior.
UIOptions?: {
  dockedSidebarBreakpoint?: number;
  canvasActions?: {
    changeViewBackgroundColor?: boolean;
    clearCanvas?: boolean;
    export?: false | ExportOpts;
    loadScene?: boolean;
    saveToActiveFile?: boolean;
    toggleTheme?: boolean | null;
    saveAsImage?: boolean;
  };
  tools?: {
    image?: boolean;
  };
  getFormFactor?: (
    editorWidth: number,
    editorHeight: number,
  ) => "desktop" | "tablet" | "phone";
};

Advanced Props

langCode
string
default:"en"
Language code for internationalization. Supported languages include en, es, fr, de, pt, ru, zh, ja, and more.
aiEnabled
boolean
default:"true"
When false, disables AI features like text-to-diagram.
showDeprecatedFonts
boolean
When true, shows deprecated font options.
children
React.ReactNode
Custom components to render inside Excalidraw, such as MainMenu, WelcomeScreen, Footer, or Sidebar.

Excalidraw API

The imperative API is provided via the excalidrawAPI prop callback:
function App() {
  const [excalidrawAPI, setExcalidrawAPI] = useState(null);

  return (
    <Excalidraw excalidrawAPI={(api) => setExcalidrawAPI(api)} />
  );
}

API Methods

  • updateScene(sceneData) - Update elements and app state
  • resetScene(opts) - Clear the canvas and reset state
  • getSceneElements() - Get current non-deleted elements
  • getSceneElementsIncludingDeleted() - Get all elements
  • getAppState() - Get current app state
  • getFiles() - Get binary files
  • refresh() - Force re-render
  • setToast(message) - Show toast notification
  • setActiveTool(tool) - Change active tool
  • setCursor(cursor) - Set custom cursor
  • resetCursor() - Reset to default cursor
  • toggleSidebar(name) - Toggle sidebar visibility
  • scrollToContent(elements, opts) - Scroll to view specific elements
  • addFiles(files) - Add binary files
  • updateLibrary(libraryItems) - Update library items

API Event Listeners

  • onChange(callback) - Listen to changes (elements, appState, files)
  • onIncrement(callback) - Listen to state increments
  • onPointerDown(callback) - Listen to pointer down events
  • onPointerUp(callback) - Listen to pointer up events
  • onScrollChange(callback) - Listen to scroll/zoom changes
  • onUserFollow(callback) - Listen to user follow events

Complete Example

import { useState } from "react";
import {
  Excalidraw,
  MainMenu,
  WelcomeScreen,
  Footer,
} from "@excalidraw/excalidraw";

function App() {
  const [excalidrawAPI, setExcalidrawAPI] = useState(null);

  const handleChange = (elements, appState, files) => {
    console.log("Scene changed:", { elements, appState, files });
  };

  const initialData = {
    elements: [
      {
        type: "rectangle",
        x: 100,
        y: 100,
        width: 200,
        height: 100,
        fillStyle: "hachure",
        strokeColor: "#000000",
        backgroundColor: "#ced4da",
      },
    ],
    appState: {
      viewBackgroundColor: "#ffffff",
      gridSize: null,
    },
  };

  return (
    <div style={{ height: "100vh" }}>
      <Excalidraw
        excalidrawAPI={(api) => setExcalidrawAPI(api)}
        onChange={handleChange}
        initialData={initialData}
        theme="light"
        name="My Drawing"
        UIOptions={{
          canvasActions: {
            changeViewBackgroundColor: true,
            clearCanvas: true,
            export: { saveFileToDisk: true },
            loadScene: true,
            saveToActiveFile: false,
            toggleTheme: true,
          },
        }}
      >
        <MainMenu>
          <MainMenu.DefaultItems.LoadScene />
          <MainMenu.DefaultItems.Export />
          <MainMenu.DefaultItems.ClearCanvas />
          <MainMenu.Separator />
          <MainMenu.DefaultItems.Help />
        </MainMenu>
        
        <WelcomeScreen>
          <WelcomeScreen.Center>
            <WelcomeScreen.Center.Logo />
            <WelcomeScreen.Center.Heading>
              Start creating amazing diagrams!
            </WelcomeScreen.Center.Heading>
            <WelcomeScreen.Center.Menu>
              <WelcomeScreen.Center.MenuItemLoadScene />
              <WelcomeScreen.Center.MenuItemHelp />
            </WelcomeScreen.Center.Menu>
          </WelcomeScreen.Center>
          <WelcomeScreen.Hints.MenuHint />
          <WelcomeScreen.Hints.ToolbarHint />
          <WelcomeScreen.Hints.HelpHint />
        </WelcomeScreen>
      </Excalidraw>
    </div>
  );
}

export default App;

See Also