From index.tsx to <App>: how the editor gets mounted and configured
Before App.handleCanvasPointerDown can ever run, three layers have to boot in order: excalidraw-app/index.tsx (a Vite entry that just mounts the excalidraw.com website), packages/excalidraw/index.tsx (the public <Excalidraw> component every npm consumer imports), and the providers <Excalidraw> mounts above App (an isolated jotai store plus i18n loading). This module traces that boot sequence and the props/UIOptions normalization that happens along the way, and draws the line between 'the library' (packages/excalidraw) and 'the app built on it' (excalidraw-app) that recurs throughout the codebase.
excalidraw-app/index.tsx: the whole website, in 17 lines
excalidraw-app/index.tsx · lines 1–17ExcalidrawApp here is imported from ./App — this repo's own excalidraw-app/App.tsx, not the App class you traced in the drawing module (that one lives at packages/excalidraw/components/App.tsx). Same word, two different components at two different layers of the stack; keeping them straight is the whole point of this module.
registerSW() registers the PWA service worker for offline support — a hosting concern of excalidraw.com specifically. Nothing under packages/excalidraw needs or knows about it.
Standard React 18 bootstrapping: createRoot + render instantiate the excalidraw-app component tree. This is the entire 'app' in the sense of a Vite project — everything else, including the editor, is pulled in as a dependency starting here.
import { StrictMode } from "react";import { createRoot } from "react-dom/client";import { registerSW } from "virtual:pwa-register";import "../excalidraw-app/sentry";import ExcalidrawApp from "./App";window.__EXCALIDRAW_SHA__ = import.meta.env.VITE_APP_GIT_SHA;const rootElement = document.getElementById("root")!;const root = createRoot(rootElement);registerSW();root.render( <StrictMode> <ExcalidrawApp /> </StrictMode>,);
ExcalidrawBase's return: providers, then App
packages/excalidraw/index.tsx · lines 185–236EditorJotaiProvider wraps everything below in editorJotaiStore — a jotai store built through jotai-scope's createIsolation(), so this editor instance's UI-state atoms are isolated from any jotai usage on the host page and from any other <Excalidraw> instance mounted alongside it.
InitializeApp only needs langCode and theme, not the full props object — it has one job (load the right language pack, show a loading screen meanwhile) and stays decoupled from everything else App is configured with.
The <App> element receives the already-normalized UIOptions and normalizedImageOptions, plus handleExcalidrawAPI (a stable callback that fans a single API instance out to both the internal ExcalidrawAPISetContext setter and the caller's onExcalidrawAPI) and defaulted primitives like aiEnabled={aiEnabled !== false}. App's constructor never has to apply a single one of these defaults itself.
{children} is the slot a caller's own JSX (passed as <Excalidraw>...</Excalidraw> children) lands in, still nested inside App's own context providers, before the three wrapper tags unwind and ExcalidrawBase's render finishes.
return ( <EditorJotaiProvider store={editorJotaiStore}> <InitializeApp langCode={langCode} theme={theme}> <App onExport={onExport} onChange={onChange} onThemeChange={onThemeChange} onIncrement={onIncrement} initialData={initialData} initialState={initialState} onExcalidrawAPI={handleExcalidrawAPI} onMount={onMount} onUnmount={onUnmount} onInitialize={onInitialize} isCollaborating={isCollaborating} onPointerUpdate={onPointerUpdate} renderTopLeftUI={renderTopLeftUI} renderTopRightUI={renderTopRightUI} langCode={langCode} viewModeEnabled={viewModeEnabled} zenModeEnabled={zenModeEnabled} gridModeEnabled={gridModeEnabled} libraryReturnUrl={libraryReturnUrl} theme={theme} name={name} renderCustomStats={renderCustomStats} UIOptions={UIOptions} onPaste={onPaste} detectScroll={detectScroll} handleKeyboardGlobally={handleKeyboardGlobally} onLibraryChange={onLibraryChange} autoFocus={autoFocus} generateIdForFile={generateIdForFile} onLinkOpen={onLinkOpen} generateLinkForSelection={generateLinkForSelection} onPointerDown={onPointerDown} onPointerUp={onPointerUp} onScrollChange={onScrollChange} onDuplicate={onDuplicate} validateEmbeddable={validateEmbeddable} renderEmbeddable={renderEmbeddable} aiEnabled={aiEnabled !== false} showDeprecatedFonts={showDeprecatedFonts} renderScrollbars={renderScrollbars} imageOptions={normalizedImageOptions} > {children} </App> </InitializeApp> </EditorJotaiProvider> );};
Check your understanding
Answered in place — nothing is graded, everything is explained. 0 / 3 passed
Which component is directly responsible for delaying render (showing a loading screen) until the requested language pack has loaded, before the <App> element beneath it appears?
excalidraw-app's <Excalidraw> call only sets UIOptions.canvasActions.toggleTheme and .export. Why does App still see values for changeViewBackgroundColor, clearCanvas, loadScene, etc.?
Where is the real-time collaboration (Collab) code defined?