Element Utilities
Utility functions for creating, mutating, and working with Excalidraw elements.
Import
import {
// Element creation
newElement,
newTextElement,
newLinearElement,
newArrowElement,
newImageElement,
newFrameElement,
// Element mutation
mutateElement,
newElementWith,
bumpVersion,
// Element queries
getNonDeletedElements,
getSceneVersion,
hashElementsVersion,
hashString,
// Element bounds
getElementAbsoluteCoords,
getElementBounds,
getCommonBounds,
getVisibleSceneBounds,
// Bounding box utilities
elementsOverlappingBBox,
isElementInsideBBox,
elementPartiallyOverlapsWithOrContainsBBox,
// Data utilities
getDataURL,
// Library utilities
parseLibraryTokensFromUrl,
useHandleLibrary,
// Text utilities
setCustomTextMetricsProvider,
// Types
CaptureUpdateAction,
} from "@excalidraw/excalidraw";
Element Creation
newElement
Creates a new generic Excalidraw element.
function newElement(
opts: {
type: ExcalidrawGenericElement["type"];
} & ElementConstructorOpts
): NonDeleted<ExcalidrawGenericElement>
Element type (e.g., “rectangle”, “ellipse”, “diamond”)
X coordinate of the element
Y coordinate of the element
Rotation angle in radians
Stroke color for the element
Fill style (“solid”, “hachure”, “cross-hatch”)
Roughness level for hand-drawn appearance
The newly created element with all properties initialized
Example:
import { newElement } from "@excalidraw/excalidraw";
const rectangle = newElement({
type: "rectangle",
x: 100,
y: 100,
width: 200,
height: 150,
strokeColor: "#000000",
backgroundColor: "#ffffff",
fillStyle: "hachure",
strokeWidth: 2,
roughness: 1,
opacity: 100,
});
newTextElement
Creates a new text element with automatic dimension calculations.
function newTextElement(
opts: {
text: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
containerId?: string | null;
lineHeight?: number;
autoResize?: boolean;
} & ElementConstructorOpts
): NonDeleted<ExcalidrawTextElement>
Font family identifier (FONT_FAMILY constant)
opts.textAlign
'left' | 'center' | 'right'
Horizontal text alignment
ID of container element (for bound text)
Whether text should auto-resize
Example:
import { newTextElement, FONT_FAMILY } from "@excalidraw/excalidraw";
const textElement = newTextElement({
text: "Hello, World!",
x: 100,
y: 100,
fontSize: 20,
fontFamily: FONT_FAMILY.Virgil,
textAlign: "center",
strokeColor: "#000000",
});
newLinearElement
Creates a line or arrow element.
function newLinearElement(
opts: {
type: "line" | "arrow";
points?: LocalPoint[];
} & ElementConstructorOpts
): NonDeleted<ExcalidrawLinearElement>
Array of points [x, y] defining the line path
Example:
import { newLinearElement } from "@excalidraw/excalidraw";
const line = newLinearElement({
type: "line",
x: 100,
y: 100,
points: [
[0, 0],
[100, 50],
[200, 100],
],
strokeColor: "#000000",
});
newArrowElement
Creates an arrow element with optional arrowheads.
function newArrowElement(
opts: {
type: "arrow";
startArrowhead?: Arrowhead | null;
endArrowhead?: Arrowhead | null;
points?: LocalPoint[];
elbowed?: boolean;
} & ElementConstructorOpts
): NonDeleted<ExcalidrawArrowElement>
Arrowhead style for start point (“arrow”, “dot”, “bar”, etc.)
Arrowhead style for end point
Whether the arrow should use elbow routing
Example:
import { newArrowElement } from "@excalidraw/excalidraw";
const arrow = newArrowElement({
type: "arrow",
x: 100,
y: 100,
points: [
[0, 0],
[200, 0],
],
startArrowhead: null,
endArrowhead: "arrow",
strokeColor: "#000000",
});
newImageElement
Creates an image element.
function newImageElement(
opts: {
type: "image";
fileId?: string | null;
status?: "pending" | "saved" | "error";
scale?: [number, number];
} & ElementConstructorOpts
): NonDeleted<ExcalidrawImageElement>
ID of the file in BinaryFiles
opts.status
'pending' | 'saved' | 'error'
Loading status of the image
Scale factors [x, y] for the image
newFrameElement
Creates a frame element for grouping.
function newFrameElement(
opts: {
name?: string;
} & ElementConstructorOpts
): NonDeleted<ExcalidrawFrameElement>
Optional name for the frame
Element Mutation
mutateElement
Mutates an existing element with updates and bumps its version.
function mutateElement<TElement extends ExcalidrawElement>(
element: TElement,
elementsMap: ElementsMap,
updates: ElementUpdate<TElement>,
options?: {
isDragging?: boolean;
}
): TElement
element
ExcalidrawElement
required
The element to mutate
Map of all elements (for context)
updates
Partial<TElement>
required
Properties to update (excludes ‘id’ and ‘updated’)
Whether the element is being dragged
The mutated element with updated version and versionNonce
Example:
import { mutateElement } from "@excalidraw/excalidraw";
mutateElement(element, elementsMap, {
x: 150,
y: 200,
width: 300,
});
newElementWith
Creates a new element instance with updates (immutable operation).
function newElementWith<TElement extends ExcalidrawElement>(
element: TElement,
updates: ElementUpdate<TElement>,
force?: boolean
): TElement
element
ExcalidrawElement
required
The base element
updates
Partial<TElement>
required
Properties to update
Force regeneration even if no changes detected
New element instance with updates applied
Example:
import { newElementWith } from "@excalidraw/excalidraw";
const updatedElement = newElementWith(element, {
backgroundColor: "#ff0000",
opacity: 80,
});
bumpVersion
Bumps element version, versionNonce, and updated timestamp.
function bumpVersion<T extends ExcalidrawElement>(
element: T,
version?: number
): T
element
ExcalidrawElement
required
The element to bump
Optional specific version to set (will be incremented by 1)
Example:
import { bumpVersion } from "@excalidraw/excalidraw";
bumpVersion(element);
Element Queries
getNonDeletedElements
Filters out deleted elements from an array.
function getNonDeletedElements<T extends ExcalidrawElement>(
elements: readonly T[]
): readonly NonDeleted<T>[]
elements
readonly ExcalidrawElement[]
required
Array of elements to filter
elements
NonDeleted<ExcalidrawElement>[]
Array of non-deleted elements
Example:
import { getNonDeletedElements } from "@excalidraw/excalidraw";
const activeElements = getNonDeletedElements(allElements);
getSceneVersion
Calculates the scene version by summing element versions.
function getSceneVersion(elements: readonly ExcalidrawElement[]): number
elements
readonly ExcalidrawElement[]
required
Elements to calculate version from
Sum of all element versions
Note: This function is deprecated. Use hashElementsVersion instead for better performance.
hashElementsVersion
Generates a hash of elements’ versionNonce values using the djb2 algorithm.
function hashElementsVersion(elements: ElementsMapOrArray): number
elements
ElementsMapOrArray
required
Elements to hash (array or Map)
Unsigned 32-bit integer hash
Example:
import { hashElementsVersion } from "@excalidraw/excalidraw";
const versionHash = hashElementsVersion(elements);
hashString
Hashes a string using the djb2 algorithm.
function hashString(s: string): number
Unsigned 32-bit integer hash
Element Bounds
getElementAbsoluteCoords
Gets absolute coordinates of an element in scene coordinates.
function getElementAbsoluteCoords(
element: ExcalidrawElement,
elementsMap: ElementsMap,
includeBoundText?: boolean
): [number, number, number, number, number, number]
element
ExcalidrawElement
required
The element to get coordinates for
Whether to include bound text in calculations
Array containing: [x1, y1, x2, y2, centerX, centerY]
Example:
import { getElementAbsoluteCoords } from "@excalidraw/excalidraw";
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(
element,
elementsMap
);
console.log(`Bounds: (${x1}, ${y1}) to (${x2}, ${y2})`);
console.log(`Center: (${cx}, ${cy})`);
getElementBounds
Gets the axis-aligned bounding box for an element.
function getElementBounds(
element: ExcalidrawElement,
elementsMap: ElementsMap,
nonRotated?: boolean
): Bounds
element
ExcalidrawElement
required
The element to get bounds for
Whether to get bounds without rotation
getCommonBounds
Gets the common bounding box for multiple elements.
function getCommonBounds(
elements: ElementsMapOrArray,
elementsMap?: ElementsMap
): Bounds
elements
ElementsMapOrArray
required
Elements to get common bounds for
Optional elements map for context
Common bounding box containing all elements
Example:
import { getCommonBounds } from "@excalidraw/excalidraw";
const [minX, minY, maxX, maxY] = getCommonBounds(selectedElements);
const width = maxX - minX;
const height = maxY - minY;
getVisibleSceneBounds
Gets the visible bounds of the canvas viewport in scene coordinates.
function getVisibleSceneBounds(state: {
scrollX: number;
scrollY: number;
width: number;
height: number;
zoom: { value: number };
}): SceneBounds
state.zoom
{ value: number }
required
Current zoom value
bounds
[sceneX, sceneY, sceneX2, sceneY2]
Visible scene bounds
Element Text
refreshTextDimensions
Recalculates text element dimensions based on content and container.
function refreshTextDimensions(
textElement: ExcalidrawTextElement,
container: ExcalidrawTextContainer | null,
elementsMap: ElementsMap,
text?: string
): { text: string; x: number; y: number; width: number; height: number } | undefined
textElement
ExcalidrawTextElement
required
The text element to refresh
container
ExcalidrawTextContainer | null
required
Container element (if text is bound)
Updated text, position, and dimensions
Bounding Box Utilities
elementsOverlappingBBox
Finds elements that overlap with, contain, or are inside a bounding box.
function elementsOverlappingBBox(opts: {
elements: readonly NonDeletedExcalidrawElement[];
bounds: Bounds | ExcalidrawElement;
errorMargin?: number;
type: "overlap" | "contain" | "inside";
}): readonly NonDeletedExcalidrawElement[];
elements
readonly NonDeletedExcalidrawElement[]
required
Elements to check against the bounding box.
bounds
Bounds | ExcalidrawElement
required
Bounding box as [x1, y1, x2, y2] or an element to use its bounds.
Safety offset in pixels to expand the bounding box.
type
'overlap' | 'contain' | 'inside'
required
overlap: Elements overlapping or inside bounds
contain: Elements inside bounds or bounds inside elements
inside: Elements inside bounds only
elements
NonDeletedExcalidrawElement[]
Array of elements matching the criteria.
Example:
import { elementsOverlappingBBox } from "@excalidraw/excalidraw";
// Find elements overlapping a selection box
const selectedElements = elementsOverlappingBBox({
elements: allElements,
bounds: [100, 100, 400, 400],
type: "overlap",
});
// Find elements completely inside a frame
const elementsInFrame = elementsOverlappingBBox({
elements: allElements,
bounds: frameElement,
type: "inside",
});
isElementInsideBBox
Checks if an element is inside a bounding box.
function isElementInsideBBox(
element: NonDeletedExcalidrawElement,
bbox: Bounds,
eitherDirection?: boolean
): boolean;
element
NonDeletedExcalidrawElement
required
Element to check.
Bounding box as [x1, y1, x2, y2].
If true, also returns true if bbox is inside element.
true if element is inside the bounding box.
Example:
import { isElementInsideBBox } from "@excalidraw/excalidraw";
const bounds = [0, 0, 500, 500];
const isInside = isElementInsideBBox(element, bounds);
if (isInside) {
console.log("Element is inside the bounds");
}
elementPartiallyOverlapsWithOrContainsBBox
Checks if an element partially overlaps with or contains a bounding box.
function elementPartiallyOverlapsWithOrContainsBBox(
element: NonDeletedExcalidrawElement,
bbox: Bounds
): boolean;
element
NonDeletedExcalidrawElement
required
Element to check.
Bounding box as [x1, y1, x2, y2].
true if element overlaps or contains the bounding box.
Example:
import { elementPartiallyOverlapsWithOrContainsBBox } from "@excalidraw/excalidraw";
const dragBox = [100, 100, 200, 200];
const overlaps = elementPartiallyOverlapsWithOrContainsBBox(element, dragBox);
if (overlaps) {
console.log("Element should be selected");
}
Data Utilities
getDataURL
Converts a Blob or File to a Data URL (async).
function getDataURL(file: Blob | File): Promise<DataURL>;
Base64-encoded data URL string.
Example:
import { getDataURL } from "@excalidraw/excalidraw";
const file = new File(["Hello"], "test.txt", { type: "text/plain" });
const dataURL = await getDataURL(file);
console.log(dataURL); // "data:text/plain;base64,SGVsbG8="
Library Utilities
parseLibraryTokensFromUrl
Extracts library installation URL and ID token from the current page URL.
function parseLibraryTokensFromUrl(): {
libraryUrl: string;
idToken: string | null;
} | null;
Object with libraryUrl and idToken, or null if not found.
Example:
import { parseLibraryTokensFromUrl } from "@excalidraw/excalidraw";
// URL: https://excalidraw.com/#addLibrary=https://example.com/lib.excalidrawlib
const tokens = parseLibraryTokensFromUrl();
if (tokens) {
console.log("Library URL:", tokens.libraryUrl);
console.log("ID Token:", tokens.idToken);
}
useHandleLibrary
Hook for handling library loading, updates, and persistence.
function useHandleLibrary(opts: {
excalidrawAPI: ExcalidrawImperativeAPI | null;
validateLibraryUrl?: (url: string) => boolean;
} & (
| { getInitialLibraryItems?: () => MaybePromise<LibraryItemsSource> }
| {
adapter: LibraryPersistenceAdapter;
migrationAdapter?: LibraryMigrationAdapter;
}
)): void;
excalidrawAPI
ExcalidrawImperativeAPI | null
required
Excalidraw API instance.
Custom validator for library installation URLs.validateLibraryUrl?: (url: string) => boolean;
adapter
LibraryPersistenceAdapter
Adapter for persisting library to storage.interface LibraryPersistenceAdapter {
load(metadata: { source: "load" | "save" }): Promise<{
libraryItems: LibraryItems;
} | null>;
save(data: { libraryItems: LibraryItems }): Promise<void>;
}
Optional adapter for migrating from legacy storage.interface LibraryMigrationAdapter {
load(): Promise<{ libraryItems: LibraryItems } | null>;
clear(): Promise<void>;
}
Example:
import { useHandleLibrary } from "@excalidraw/excalidraw";
function MyEditor() {
const [excalidrawAPI, setExcalidrawAPI] = useState(null);
useHandleLibrary({
excalidrawAPI,
adapter: {
async load() {
const data = localStorage.getItem("excalidraw-library");
return data ? JSON.parse(data) : null;
},
async save({ libraryItems }) {
localStorage.setItem(
"excalidraw-library",
JSON.stringify({ libraryItems })
);
},
},
});
return <Excalidraw excalidrawAPI={(api) => setExcalidrawAPI(api)} />;
}
Text Utilities
setCustomTextMetricsProvider
Sets a custom text metrics provider for measuring text dimensions.
function setCustomTextMetricsProvider(
provider: (
text: string,
font: string
) => {
width: number;
height: number;
}
): void;
Function that measures text and returns width/height.provider: (text: string, font: string) => {
width: number;
height: number;
};
Example:
import { setCustomTextMetricsProvider } from "@excalidraw/excalidraw";
// Use a custom text measurement implementation
setCustomTextMetricsProvider((text, font) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.font = font;
const metrics = ctx.measureText(text);
return {
width: metrics.width,
height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
};
});
Types
CaptureUpdateAction
Enum-like object that controls when element updates are captured in the undo/redo history.
const CaptureUpdateAction = {
IMMEDIATELY: "IMMEDIATELY",
NEVER: "NEVER",
EVENTUALLY: "EVENTUALLY",
};
type CaptureUpdateActionType = ValueOf<typeof CaptureUpdateAction>;
Values:
IMMEDIATELY - Updates are immediately undoable. Use for most local updates.
NEVER - Updates never make it to undo/redo stack. Use for remote updates or scene initialization.
EVENTUALLY - Updates will eventually be captured as part of a future increment.
Example:
import { CaptureUpdateAction } from "@excalidraw/excalidraw";
// When updating scene programmatically
excalidrawAPI.updateScene({
elements: newElements,
captureUpdate: CaptureUpdateAction.NEVER, // Don't add to undo stack
});
// When updating in response to user action
excalidrawAPI.updateScene({
elements: modifiedElements,
captureUpdate: CaptureUpdateAction.IMMEDIATELY, // Allow undo
});
See Also