Skip to main content

Package Installation

1

Install via npm, yarn, or pnpm

Excalidraw requires React and React DOM as peer dependencies. Install the package using your preferred package manager:
npm install react react-dom @excalidraw/excalidraw
React Version Support: Excalidraw supports React 17, 18, and 19. The package is compatible with react@^17.0.2 || ^18.2.0 || ^19.0.0.
2

Import Excalidraw and styles

Import the Excalidraw component and its required CSS file in your application:
import { Excalidraw } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";
3

Add the component to your app

Add Excalidraw to your component. Make sure the parent container has explicit dimensions:
export default function App() {
  return (
    <div style={{ height: "500px", width: "100%" }}>
      <Excalidraw />
    </div>
  );
}
Container Dimensions Required: Excalidraw takes 100% of the width and height of its containing block. Ensure the parent element has non-zero dimensions, or the canvas will not be visible.

Framework-Specific Setup

Next.js

Next.js requires dynamic imports with SSR disabled to avoid hydration issues.
1

Create a wrapper component

Create a client component that imports Excalidraw:
excalidrawWrapper.tsx
"use client";
import { Excalidraw } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";

const ExcalidrawWrapper = () => {
  return <Excalidraw />;
};

export default ExcalidrawWrapper;
2

Import with dynamic loading

In your page component, use Next.js dynamic imports with ssr: false:
app/page.tsx
import dynamic from "next/dynamic";
import Script from "next/script";

const ExcalidrawWithClientOnly = dynamic(
  async () => (await import("../excalidrawWrapper")).default,
  {
    ssr: false,
  },
);

export default function Page() {
  return (
    <>
      <Script id="load-env-variables" strategy="beforeInteractive">
        {`window["EXCALIDRAW_ASSET_PATH"] = window.origin;`}
      </Script>
      <div style={{ height: "100vh" }}>
        <ExcalidrawWithClientOnly />
      </div>
    </>
  );
}

Vite

Vite works out of the box with Excalidraw. Simply import and use:
import { Excalidraw } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";

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

export default App;

Create React App

Create React App also works without additional configuration:
import React from "react";
import { Excalidraw } from "@excalidraw/excalidraw";
import "@excalidraw/excalidraw/index.css";

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

export default App;

Self-Hosting Fonts

For production deployments, you should self-host Excalidraw fonts instead of loading them from a CDN.
1

Copy font files to your public directory

Copy the fonts from node_modules/@excalidraw/excalidraw/dist/prod/fonts to your public directory:
cp -r node_modules/@excalidraw/excalidraw/dist/prod/fonts public/fonts
The fonts directory includes all font families used by Excalidraw: Virgil (hand-drawn style), Cascadia, Assistant, and more.
2

Set the asset path

Configure window.EXCALIDRAW_ASSET_PATH to point to your public directory where fonts are hosted:In HTML:
<script>
  window.EXCALIDRAW_ASSET_PATH = "/";
</script>
In Next.js:
import Script from "next/script";

export default function Page() {
  return (
    <>
      <Script id="load-env-variables" strategy="beforeInteractive">
        {`window.EXCALIDRAW_ASSET_PATH = window.origin;`}
      </Script>
      {/* Your Excalidraw component */}
    </>
  );
}
In React:
useEffect(() => {
  window.EXCALIDRAW_ASSET_PATH = "/";
}, []);
If you don’t set EXCALIDRAW_ASSET_PATH, Excalidraw will attempt to load fonts from the CDN at https://esm.run/@excalidraw/excalidraw/dist/prod/. This works fine for development but may cause issues in production or offline environments.

Browser Compatibility

Excalidraw supports modern browsers with the following minimum versions:

Chrome / Edge

Version 70+

Firefox

Latest version

Safari

Version 12+

Mobile Browsers

Safari iOS 12+, Chrome Android
Not supported:
  • Internet Explorer (any version)
  • Opera Mini
  • UC Browser < 13
  • Samsung Internet < 10
  • KaiOS ≤ 2.5

TypeScript Support

Excalidraw is written in TypeScript and includes full type definitions. No additional @types packages are needed.
import type {
  ExcalidrawImperativeAPI,
  ExcalidrawProps,
  NonDeletedExcalidrawElement,
  AppState,
} from "@excalidraw/excalidraw/types";

const MyComponent = () => {
  const [excalidrawAPI, setExcalidrawAPI] = 
    useState<ExcalidrawImperativeAPI | null>(null);

  return (
    <Excalidraw
      excalidrawAPI={(api) => setExcalidrawAPI(api)}
      onChange={(elements: readonly NonDeletedExcalidrawElement[], state: AppState) => {
        console.log("Elements:", elements);
      }}
    />
  );
};

Available Type Exports

Import types from the appropriate subpackages:
// Core types
import type { ExcalidrawProps, AppState } from "@excalidraw/excalidraw/types";

// Element types
import type { 
  ExcalidrawElement, 
  NonDeletedExcalidrawElement,
  FileId 
} from "@excalidraw/excalidraw/element/types";

// Data types
import type { ImportedLibraryData } from "@excalidraw/excalidraw/data/types";

Additional Packages

Excalidraw exports additional utility packages for advanced use cases:
Common utilities and constants:
import { THEME, MIME_TYPES, normalizeLink } from "@excalidraw/common";
Element manipulation utilities:
import { 
  mutateElement, 
  newElementWith,
  getSceneVersion,
  getNonDeletedElements 
} from "@excalidraw/element";
Mathematical utilities for geometry calculations:
import { rotatePoint, getDistance } from "@excalidraw/math";
Export and utility functions:
import { exportToCanvas, exportToSvg, exportToBlob } from "@excalidraw/utils/export";

Using the Latest (Unreleased) Version

To try unreleased features and bug fixes before the next stable release:
npm install @excalidraw/excalidraw@next
The @next tag includes unreleased changes that may be unstable. Only use this in development or if you need a specific fix that hasn’t been released yet.

Next Steps