Menu

Element System

Relevant source files

Purpose and Scope

The Element System defines the core data model for all drawable entities in Excalidraw. This document covers the element type hierarchy, element lifecycle (creation, mutation, deletion), storage mechanisms, and high-level element relationships. For detailed information about specific subsystems, see:

Element Data Model

Core Element Type

All drawable entities in Excalidraw are represented by ExcalidrawElement objects. The type hierarchy consists of a base interface with common properties and specialized types for different shapes.

Base Properties (All Elements)

PropertyTypePurpose
idstringUnique identifier
type"rectangle" | "ellipse" | "diamond" | "arrow" | "line" | "freedraw" | "text" | "image" | "frame" | "magicframe" | "embeddable" | "iframe"Element shape type
x, ynumberTop-left position in scene coordinates
width, heightnumberElement dimensions
angleRadiansRotation angle
versionnumberIncremented on each mutation
versionNoncenumberRandom value changed on mutation
isDeletedbooleanSoft deletion flag
indexFractionalIndexZ-order position (see Fractional Indexing)
groupIdsGroupId[]Group membership
frameIdstring | nullContaining frame (see Frames)
boundElementsBoundElement[] | nullElements bound to this element (see Binding)
updatednumberTimestamp of last update
linkstring | nullHyperlink URL
lockedbooleanPrevents editing

Style Properties

PropertyType
strokeColorstring
backgroundColorstring
fillStyle"solid" | "hachure" | "cross-hatch"
strokeWidthnumber
strokeStyle"solid" | "dashed" | "dotted"
roughnessnumber (0-2)
opacitynumber (0-100)
roundnessStrokeRoundness | null

Sources: packages/excalidraw/types.ts247-270 packages/element/src/types.ts

Element Type Hierarchy

Sources: packages/excalidraw/types.ts14-36 packages/element/src/types.ts

Immutability and Versioning

Elements follow an immutable update pattern. Direct mutation is prohibited; instead, updates create new element versions:

  • version: Monotonically increasing integer, incremented on every mutation
  • versionNonce: Random integer regenerated on mutation, used for conflict detection in multiplayer scenarios
  • updated: Timestamp in milliseconds for tracking element freshness

The mutateElement function is the primary mechanism for updating elements while maintaining immutability invariants.

Sources: packages/element/src/mutateElement.ts1-100 packages/excalidraw/components/App.tsx110-243

Element Lifecycle

Element Creation

Constructor Functions

Element creation uses type-specific constructor functions located in the @excalidraw/element package:

FunctionCreates
newElement()Generic elements (rectangle, ellipse, diamond)
newLinearElement()Line elements
newArrowElement()Arrow elements
newTextElement()Text elements
newImageElement()Image elements
newFreeDrawElement()Freedraw elements
newFrameElement()Frame elements
newMagicFrameElement()Magic frame elements
newIframeElement()Iframe elements
newEmbeddableElement()Embeddable elements

Each constructor:

  1. Generates a unique id via randomId()
  2. Sets initial position (x, y)
  3. Initializes dimensions (width, height)
  4. Sets version: 1, random versionNonce, and current updated timestamp
  5. Applies default style properties (colors, stroke width, etc.)
  6. Computes type-specific properties (e.g., points for linear elements)

Sources: packages/excalidraw/components/App.tsx110-243 packages/element/src/newElement.ts

High-Level Creation via convertToExcalidrawElements

For declarative element creation, use convertToExcalidrawElements which accepts simplified ExcalidrawElementSkeleton objects:

This function:

  • Fills in missing required properties with defaults
  • Handles complex element creation (arrows with bindings, text labels, etc.)
  • Manages element relationships (binding, containment)
  • Syncs fractional indices for proper z-ordering

Sources: packages/excalidraw/data/transform.ts1-500 packages/excalidraw/data/transform.test.ts

Element Mutation

mutateElement Function

The canonical way to update elements. Never modify element properties directly.

Behavior:

  1. Creates a shallow clone of the element
  2. Applies property updates from updates object
  3. Increments version
  4. Regenerates versionNonce (random integer)
  5. Updates updated timestamp
  6. Invalidates shape cache if geometry changes
  7. Special handling for elbow arrows (recalculates routing)
  8. Returns the new element instance

The informMutation parameter (default true) controls whether the mutation triggers observable change detection.

Sources: packages/element/src/mutateElement.ts40-150

newElementWith Helper

A lightweight alternative that creates a new element with updated properties without triggering mutation side effects:

Does not increment version or versionNonce, primarily used for temporary or ephemeral updates.

Sources: packages/element/src/mutateElement.ts20-38 packages/excalidraw/components/App.tsx110-243

Element Deletion

Elements use soft deletion via the isDeleted flag. Deleted elements remain in the scene but are filtered out during rendering and most operations.

Benefits:

  • Supports undo/redo (restore by setting isDeleted: false)
  • Maintains references for bound elements (arrows, text)
  • Enables multiplayer synchronization (deletion propagates as a state change)

Hard deletion (removing from scene completely) is rare and typically only occurs during:

  • History cleanup
  • Garbage collection of old deleted elements
  • Scene reset operations

Sources: packages/element/src/typeChecks.ts packages/excalidraw/components/App.tsx232-239

Element Storage and Management

Scene Class

The Scene class manages the canonical collection of elements in the application.

Key Methods

MethodReturnsPurpose
getElementsIncludingDeleted()ExcalidrawElement[]All elements (including deleted)
getNonDeletedElements()OrderedExcalidrawElement[]Only visible elements, sorted by z-order
getNonDeletedElementsMap()NonDeletedSceneElementsMapMap of visible elements
replaceAllElements(elements)voidReplace entire element collection
insertElementAtIndex(element, index)voidInsert element at specific position
getElement(id)ExcalidrawElement | nullRetrieve element by ID

The scene maintains cached sorted arrays and maps for performance. Caches are invalidated and rebuilt when elements change via triggerUpdate().

Sources: packages/element/src/Scene.ts1-400

SceneElementsMap

A Map<string, ExcalidrawElement> used throughout the codebase for efficient element lookup by ID.

Helper functions:

  • arrayToMap(elements): Convert array to map
  • isNonDeletedElement(element): Type guard for non-deleted elements

Sources: packages/element/src/types.ts packages/element/src/Scene.ts1-100

Store and Delta Tracking

The Store class captures observable element changes and emits them as delta events for history and collaboration.

Delta System

The delta system tracks incremental changes:

  • ElementsDelta: Captures added, removed, and updated elements

    • added: Map of newly created elements
    • removed: Map of deleted elements
    • updated: Map of element property changes (only changed properties included)
  • AppStateDelta: Captures observable app state changes (selection, groups, etc.)

  • StoreDelta: Combines ElementsDelta + AppStateDelta

Store Commit Flow

  1. User action modifies elements/appState
  2. Store.commit(elements, appState) called
  3. Store compares against last snapshot
  4. Calculates StoreDelta (only changed properties)
  5. Emits DurableIncrement (for history) or EphemeralIncrement (transient, e.g., dragging)
  6. Updates snapshot to current state

Sources: packages/element/src/store.ts1-300 packages/element/src/delta.ts1-400

Element Relationships

Binding

Elements can be bound to each other to create relationships:

  • Arrow binding: Arrows bind to shapes at start/end points (see Element Binding System)
  • Text binding: Text elements bind to container shapes

Binding information is stored bidirectionally:

  • Arrow stores startBinding / endBinding with target element ID
  • Bound shape stores reference in boundElements array

Sources: packages/element/src/binding.ts packages/excalidraw/components/App.tsx110-243

Groups

Elements can belong to multiple groups via the groupIds array property. Groups enable collective selection and manipulation.

Group operations:

  • getElementsInGroup(elements, groupId): Get all elements in a group
  • getNonDeletedGroupIds(elements): Get all active group IDs
  • selectGroupsForSelectedElements(): Auto-select parent groups when selecting grouped elements

Sources: packages/element/src/groups.ts packages/excalidraw/components/App.tsx211-217

Frames

Frames provide spatial containment for elements (see Frames and Containment):

Frame-related operations:

  • getFrameChildren(scene, frameId): Get all elements in a frame
  • elementOverlapsWithFrame(element, frame): Check spatial containment
  • getContainingFrame(element, elementsMap): Find parent frame

Sources: packages/element/src/frame.ts packages/excalidraw/components/App.tsx176-190

Z-Order and Fractional Indexing

Elements are ordered using fractional indices (see Fractional Indexing and Z-Order):

Key functions:

  • syncInvalidIndices(elements): Ensure valid fractional indices
  • syncMovedIndices(elements, indices): Update indices after reordering
  • orderByFractionalIndex(elements): Sort elements by index

The fractional index system enables collaborative ordering without conflicts.

Sources: packages/element/src/fractionalIndex.ts packages/excalidraw/components/App.tsx218-219

Element Operations

Duplication

duplicateElement

Creates a deep copy of a single element with a new ID:

Handles:

  • New unique id generation
  • Group ID remapping for duplicated groups
  • Preserves element relationships (with ID updates)
  • Applies optional property overrides
  • Deep clones nested properties (points, bound elements, etc.)

duplicateElements

Bulk duplication with relationship preservation:

Advanced features:

  • Maintains binding relationships between duplicated elements
  • Updates arrow bindings to point to cloned shapes
  • Adjusts frame membership
  • Optionally randomizes seeds (for visual variation)
  • Applies position offset to avoid overlap

Sources: packages/element/src/duplicate.ts1-400 packages/element/tests/duplicate.test.tsx

Transformation

The convertToExcalidrawElements function transforms simplified element skeletons into full ExcalidrawElement objects:

Features

  • Fills default values for missing properties
  • Automatically binds arrows to shapes
  • Creates text labels for arrows
  • Wraps text in containers
  • Computes bounding boxes
  • Assigns fractional indices
  • Validates and fixes data

Example: Arrow with Bindings

Sources: packages/excalidraw/data/transform.ts1-800 packages/excalidraw/data/transform.test.ts1-500


Summary

The Element System provides:

  1. A type-safe, immutable data model for all drawable entities
  2. Versioned element mutations with conflict detection support
  3. Efficient storage and lookup via Scene and SceneElementsMap
  4. Delta-based change tracking for history and collaboration
  5. Rich element relationships (binding, grouping, frames, z-order)
  6. Comprehensive duplication and transformation utilities

This architecture enables Excalidraw's core features: undo/redo, real-time collaboration, complex element interactions, and performant rendering.