Frontend Development 10 min read

Redesigning Excalidraw’s Component API: From Render Props to Child Components

The article explains how Excalidraw’s new component API replaces render props with a child‑component approach, introduces customizable MainMenu, Footer, and WelcomeScreen components, provides code examples, and discusses the benefits and limitations of this redesign for developers building custom whiteboard applications.

KooFE Frontend Team
KooFE Frontend Team
KooFE Frontend Team
Redesigning Excalidraw’s Component API: From Render Props to Child Components
This article is a translation of “Rethinking the Component API” for Excalidraw, a popular hand‑drawn style whiteboard app that provides an editor and related components for developers.

Since the redesign announcement last year, many developers asked when the new API would be released to the Excalidraw package and why it wasn’t available from the start.

The delay was due to the need to support custom development. In the public app, some content such as the main menu and welcome screen is hard‑coded, which many private applications don’t need, so a more flexible API was required.

Today the initial version of the new API is released; the previously blocking features are now customizable. If feedback is positive, more APIs will be opened to let developers tailor the editor to their users’ needs.

The redesign introduces two major UI pieces: a dropdown menu in the top‑left corner (MainMenu) and a welcome screen with tips for new users.

Dropping render props

Instead of using render props, the new API lets you render any component as a child of

Excalidraw

. Example:

<code>import { Excalidraw, MainMenu, Footer } from '@excalidraw/excalidraw';
import { MyCustomButton } from './MyCustomButton';

export const App = () => (
  <Excalidraw>
    <MainMenu>{/* menu items */}</MainMenu>
    <Footer>
      <MyCustomButton />
    </Footer>
  </Excalidraw>
);
</code>

Future versions may expose plugins as components, e.g.:

<code>import { Excalidraw, MinimapPlugin } from "@excalidraw/excalidraw";

export const App = () => (
  <Excalidraw>
    <MainMenu>{/* menu items */}</MainMenu>
    <MinimapPlugin />
  </Excalidraw>
);
</code>

This change is more of an aesthetic decision; the API surface is smaller because you no longer need to pass render props.

The goal is also to separate UI from the editor core, making the core usable without React.

To identify which children correspond to which UI parts, we use the legacy

React.Children

API. Simplified utility:

<code>export const getReactChildren = <ExpectedChildren extends {
  [k in string]?: React.ReactNode;
}>(children: React.ReactNode) => {
  return React.Children.toArray(children).reduce((acc, child) => {
    if (React.isValidElement(child)) {
      acc[child.type.displayName] = child;
    }
    return acc;
  }, {} as Partial<ExpectedChildren>);
};
</code>

In practice we validate expected child names and render them accordingly, allowing any UI component to be a top‑level child of

Excalidraw

without worrying about order.

Limitation: the component must be a direct child of

Excalidraw

. Nesting a

Footer

inside another component prevents detection, e.g.:

<code>const MyFooter = () => {
  return <Footer />;
};

const App = () => (
  <Excalidraw>
    {/* nope :( */}
    <MyFooter />
  </Excalidraw>
);
</code>

&lt;MainMenu/&gt;

The new editor design adds a dropdown menu in the top‑left corner, which can be fully customized.

Below is the menu on excalidraw.com (left) versus the default menu rendered from the package (right).

MainMenu comparison
MainMenu comparison

If the default options don’t suit you, you can render your own

MainMenu

component, using either the built‑in menu items or completely custom ones.

<code>import { Excalidraw, MainMenu } from "@excalidraw/excalidraw";

const App = () => (
  <Excalidraw>
    <MainMenu>
      <MainMenu.DefaultItems.LoadScene />
      <MainMenu.DefaultItems.Export />
      <MainMenu.DefaultItems.SaveAsImage />
      <MainMenu.Separator />
      <MainMenu.Item onSelect={() => alert("Hello to you too!")}>Hello!</MainMenu.Item>
    </MainMenu>
  </Excalidraw>
);
</code>

As with

Footer

, ensure it is a top‑level child of

Excalidraw

.

&lt;WelcomeScreen/&gt;

The redesign also introduces a

WelcomeScreen

component, which is composed of several sub‑elements rendered in different UI locations.

The two main parts are a central area with a logo and quick actions, and hint components that point out UI features.

WelcomeScreen layout
WelcomeScreen layout

You can customize most of the content, rendering only the center part, changing hints, etc. Note that

WelcomeScreen

must be a top‑level child, and its subcomponents like

WelcomeScreen.Center

and

WelcomeScreen.Hints

must be direct children of

WelcomeScreen

.

<code>import { Excalidraw, WelcomeScreen } from "@excalidraw/excalidraw";

const App = () => (
  <Excalidraw>
    <WelcomeScreen>
      <WelcomeScreen.Hints.ToolbarHint />
      <WelcomeScreen.Center>
        <WelcomeScreen.Center.Logo />
        <WelcomeScreen.Center.Heading>You can draw anything you want!</WelcomeScreen.Center.Heading>
        <WelcomeScreen.Center.Menu>
          <WelcomeScreen.Center.MenuItemHelp />
          <WelcomeScreen.Center.MenuItemLiveCollaborationTrigger onSelect={() => setCollabDialogShown(true)} />
          {!isExcalidrawPlusSignedUser && (
            <WelcomeScreen.Center.MenuItem onSelect={() => console.log("doing something!")}>Do something</WelcomeScreen.Center.MenuItem>
          )}
        </WelcomeScreen.Center.Menu>
      </WelcomeScreen.Center>
    </WelcomeScreen>
  </Excalidraw>
);
</code>

Summary

You can now read more about the newly introduced APIs in the documentation. We are improving the docs and will soon publish detailed examples on handling specific cases. Stay tuned! 💜

Frontend DevelopmentReactUI CustomizationExcalidrawComponent API
KooFE Frontend Team
Written by

KooFE Frontend Team

Follow the latest frontend updates

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.