ng-whiteboard
ng-whiteboard is a feature-rich, modular, and flexible whiteboard library for Angular. Designed for ease of use, performance, and a seamless drawing experience. It provides essential drawing tools and features with a scalable architecture.
Features
- SVG-based rendering for high-quality visuals
- Optimized performance for smooth interactions
- Modular, tree-shakable, and lightweight architecture
- Comprehensive Public API via
WhiteboardServiceand component bindings - Undo/Redo, Zoom, Pan, and Save functionalities
- Multiple drawing tools (pen, shapes, text, eraser, hand tool, etc.)
- Multi-instance support - Run multiple independent whiteboards simultaneously
- Keyboard shortcuts - Full keyboard support for common operations
- Context menu - Right-click menu for quick actions
- Layer management - Control element z-index and stacking order
- Copy/Paste/Cut - Full clipboard support for elements
- Selection tools - Select, move, resize, and rotate elements
- Arrows - Arrows with customizable heads, and smart element binding
- Future-proof and scalable design
Installation
Install via yarn:
yarn add ng-whiteboard
or npm:
npm install ng-whiteboard
Integration
For Standalone Components
Import the component directly in your standalone component:
import { Component } from '@angular/core';
import { NgWhiteboardComponent } from 'ng-whiteboard';
@Component({
selector: 'my-component',
imports: [NgWhiteboardComponent],
template: '<ng-whiteboard></ng-whiteboard>',
})
export class MyComponent {}
For NgModules
Import the component in your app.module.ts:
import { NgWhiteboardComponent } from 'ng-whiteboard';
@NgModule({
imports: [NgWhiteboardComponent],
// other imports
})
export class AppModule {}
Usage
Basic Example
<ng-whiteboard></ng-whiteboard>
This renders the board with the built-in editor. For the canvas alone, under your own UI, use <ng-whiteboard [showEditor]="false">.
Advanced Example With Persist Data
import { Component, OnInit } from '@angular/core';
import { WhiteboardService } from 'ng-whiteboard';
@Component({
selector: 'app-whiteboard-container',
templateUrl: './whiteboard-container.component.html',
styleUrls: ['./whiteboard-container.component.css'],
})
export class WhiteboardContainerComponent implements OnInit {
whiteboardOptions: WhiteboardOptions = {
backgroundColor: '#fff',
strokeColor: '#2c80b1',
strokeWidth: 5,
};
constructor(private whiteboardService: WhiteboardService) {}
ngOnInit() {
const savedData = localStorage.getItem('whiteboardData');
if (savedData) {
this.data = JSON.parse(savedData);
}
}
onDataChange(data: WhiteboardElement[]) {
localStorage.setItem('whiteboardData', JSON.stringify(data));
}
clearBoard() {
this.whiteboardService.clear();
}
}
Component Integration
<ng-whiteboard (dataChange)="onDataChange($event)" [options]="whiteboardOptions"></ng-whiteboard>
Built-in Editor
<ng-whiteboard [config]="{ theme: 'dark' }"></ng-whiteboard>
- The editor (toolbar, properties, layers) is on by default.
[showEditor]="false"renders only the canvas, for example under a custom editor built withNgWhiteboardService. - The editor is lazy-loaded (
@defer), so it appears just after the canvas. With SSR, no editor markup is rendered until the page hydrates. config.themeis'light' | 'dark'. Unset renders as before (light).- The layout adapts to the editor's own container. Phones and small containers get a bottom toolbar and bottom sheets.
- Touch: pinch to zoom and two-finger pan work with or without the editor.
Alt + Ptoggles the properties panel.- Toolbar: each tool has a letter shortcut and the visible tools are numbered
1–0.Qlocks the current tool so it stays active after each shape,Zzooms to a dragged area, and the image tool opens a file picker. On phones the shape tools collapse into one button. config.toolbarTools(aToolType[]) limits which tools the toolbar shows; hidden tools also lose their shortcuts.config.toolbarPositionis'bottom'(default) or'left';'left'falls back to the bottom on compact screens.- The properties panel adapts to the selected shape: arrow heads, arrow path and line ends for arrows, corner radius for rectangles, brush for the pen, and so on. The optional
config.cornerRadiussets the corner radius of new rectangles (default5). - The header has a main menu (☰) with Open…, Save, Save as…, Export image…, Copy as PNG, Dark/Light mode and Reset canvas…, an editable board title, and a layers button. Shortcuts (editor only, focused board):
Ctrl/Cmd + Oopen,Ctrl/Cmd + Ssave,Ctrl/Cmd + Shift + Ssave as,Ctrl/Cmd + Shift + Eexport image,Ctrl/Cmd + Shift + Ccopy as PNG. - Save writes a
.jsonboard file. In Chrome and Edge the first save asks where to put it and later saves overwrite that file; opening a.jsonfile links it the same way. Other browsers download a copy on every save, and the menu shows Save to file instead of Save / Save as…. - After the board has been saved or opened, a dot after the title shows unsaved changes; undoing back to the saved state clears it.
- Export image… includes the board data in the PNG or SVG by default ("Include board data"), so Open… can load the image back for editing.
- Export image… opens a dialog with a live preview, PNG or SVG, scale (1×/2×/3×), background on/off, an "only selected" option, a file name, and Download or Copy.
- Layers panel: rename (double-click,
EnterorF2), reorder by drag orAlt + Arrow, eye and lock toggles, and a ⋯ menu with opacity, blend mode, duplicate, merge down, and delete (with a confirm and a "move elements to the layer below" option). - Open, Reset and layer operations are undoable (one step each).
EditorConfigflags other thantitleare deprecated and ignored. They will be removed in the next major version.
Configuration
| Input | Type | Default | Description |
|---|---|---|---|
[data] |
WhiteboardElement[] |
[] |
The whiteboard data |
[options] |
WhiteboardOptions |
null |
Component configuration object, properties described below |
[showEditor] |
boolean |
true |
Show the built-in editor; false renders only the canvas |
[drawingEnabled] |
boolean |
true |
Enable mouse/touch interactions |
[selectedTool] |
ToolType |
ToolType.Pen |
The current selected tool |
[canvasWidth] |
number |
800 |
The width of whiteboard canvas |
[canvasHeight] |
number |
600 |
The height of whiteboard canvas |
[fullScreen] |
boolean |
true |
If true, change (canvasWidth, canvasHeight) to fit the parent container |
[strokeColor] |
string |
#333333 |
The default stroke color |
[backgroundColor] |
string |
#F8F9FA |
The default background color |
[fill] |
string |
transparent |
The default fill color |
[strokeWidth] |
number |
2 |
The default stroke width |
[zoom] |
number |
1 |
Zoom level |
[fontFamily] |
string |
sans-serif |
The default font family |
[fontSize] |
number |
24 |
The default font size |
[center] |
boolean |
true |
Center the canvas in parent component, works with fullScreen: false |
[x] |
number |
0 |
If center is false, set the X axis |
[y] |
number |
0 |
If center is false, set the Y axis |
[enableGrid] |
boolean |
false |
Enable the grid pattern |
[gridSize] |
number |
10 |
Set the grid inner boxes size |
[snapToGrid] |
boolean |
false |
Enable snapping to grid |
[lineJoin] |
LineJoin |
LineJoin.Miter |
The default Line join |
[lineCap] |
LineCap |
LineCap.Butt |
The default Line cap |
[dasharray] |
string |
'' |
The default dash-array |
[dashoffset] |
number |
0 |
The default dash-offset |
[arrowConfig] |
ArrowConfig |
See below | Arrow-specific configuration (heads, line style). See Arrow Configuration |
Arrow Configuration
The arrowConfig property controls the default appearance of newly drawn arrows.
import { ArrowConfig } from 'ng-whiteboard';
const config: Partial<WhiteboardConfig> = {
arrowConfig: {
startHeadStyle: 'none',
endHeadStyle: 'open-arrow',
lineStyle: 'curve',
},
};
<ng-whiteboard [config]="config"></ng-whiteboard>
ArrowConfig Properties
| Property | Type | Default | Description |
|---|---|---|---|
startHeadStyle |
ArrowHeadStyle |
'none' |
Arrowhead style at the start of the arrow |
endHeadStyle |
ArrowHeadStyle |
'open-arrow' |
Arrowhead style at the end of the arrow |
lineStyle |
ArrowLineStyle |
'curve' |
Default path type for new arrows |
ArrowHeadStyle Values
| Value | Description |
|---|---|
'none' |
No arrowhead |
'arrow' |
Filled triangle |
'open-arrow' |
Open V-chevron (stroked) |
'diamond' |
Filled diamond |
'open-diamond' |
Open diamond outline |
'circle' |
Filled circle |
'open-circle' |
Open circle outline |
'bar' |
Vertical bar (perpendicular line) |
ArrowLineStyle Values
| Value | Description |
|---|---|
'straight' |
Direct line between start and end points |
'curve' |
Smooth quadratic curve with a draggable control point |
'elbow' |
Right-angle (orthogonal) connector with a configurable bend position |
Arrow Drawing Modifiers
| Modifier | Behavior |
|---|---|
Shift + Drag |
Constrains arrow angle to 15° increments |
| Drag near element | Auto-snaps to connection points (20px snap radius) |
Smart Element Binding
Arrows can automatically bind to other elements (rectangles, ellipses, images, and text). When an arrow endpoint is dragged near a connectable element, it snaps to the nearest connection point and creates a binding. Bound arrows automatically update their position when the connected element is moved or resized.
Connection Points per Shape:
| Shape | Connection Points |
|---|---|
| Rectangle | 8 points — top, right, bottom, left, and 4 corners |
| Ellipse | 8 points — cardinal directions and 45° positions on the ellipse |
| Image | 4 cardinal points (top, right, bottom, left) |
| Text | 4 cardinal points (top, right, bottom, left) |
API Reference
Important: Multi-Instance Support
ng-whiteboard supports multiple independent whiteboard instances. When using WhiteboardService, you must specify which board you're working with:
import { Component, AfterViewInit, inject } from '@angular/core';
import { NgWhiteboardService } from 'ng-whiteboard';
@Component({
template: ` <ng-whiteboard [boardId]="boardId"></ng-whiteboard> `,
providers: [NgWhiteboardService],
})
export class MyWhiteboardComponent implements AfterViewInit {
private whiteboardService = inject(NgWhiteboardService);
boardId = 'my-unique-board-id';
ngAfterViewInit() {
// IMPORTANT: Set the active board before using service methods
this.whiteboardService.setActiveBoard(this.boardId);
}
clearBoard() {
// Now this works on the correct board
this.whiteboardService.clear();
}
}
WhiteboardService Methods
Multi-Instance Management
setActiveBoard(boardId: string)Sets the specified board as active. All service operations will target this board.activeBoard()Returns the ID of the currently active board, ornullif no board is active.clearActiveBoard()Clears the active board.getAllBoards()Returns an array of all registered board IDs.getBoardCount()Returns the total number of registered boards.hasBoard(boardId: string)Checks if a board with the specified ID exists.
Reactive Signals (Active Board)
elements: Signal<WhiteboardElement[]>Returns elements from the active board.elementsCount: Signal<number>Returns the number of elements on the active board.hasElements: Signal<boolean>Returnstrueif the active board has any elements.
Element Management
addElement(element: WhiteboardElement)Adds a new element (e.g., shape, text) to the whiteboard.addImage(image: string, x?: number, y?: number)Adds an image to the whiteboard at a specified position.removeElements(ids: string[])Removes elements from the whiteboard by IDs.updateElement(element: WhiteboardElement)Updates an existing element with new properties.updateSelectedElements(partialElement: Partial<WhiteboardElement>)Modifies only specific properties of the currently selected element.selectElements(elementsOrIds: WhiteboardElement | WhiteboardElement[] | string | string[])Select element(s) on the whiteboard.deselectElement(elementOrId: WhiteboardElement | string)Deselects a specific element on the whiteboard.toggleSelection(elementOrId: WhiteboardElement | string)Toggle the selection of an element on the whiteboard.selectAll()Selects all elements currently present on the whiteboard.clearSelection()Clears any currently selected elements on the whiteboard.
State Management
clear()Clears all elements from the whiteboard.undo()Reverts the last action.redo()Restores the last undone action.save(format = FormatType.Base64, name = 'whiteboard', options?: ExportOptions)Saves the current whiteboard in the specified format (e.g., Base64, JSON, SVG, PNG).ExportOptionsis{ scale?: number; background?: boolean; padding?: number; onlySelected?: boolean; embedBoardData?: boolean }. WithembedBoardData, a downloaded PNG or SVG also carries the board, so it can be opened again for editing.copyToClipboard(format: FormatType.Png | FormatType.Svg, options?: ExportOptions)Copies the board image to the clipboard.resetBoard()Clears elements and layers back to a fresh board (undoable).hasContent()Returnstrueif the board has any elements.
Drawing Tools & Interaction
setActiveTool(tool: ToolType)Sets the current drawing tool (e.g., pen, eraser, shape).
Canvas Control
setCanvasDimensions(width: number, height: number)Sets the width and height of the whiteboard canvas.setCanvasPosition(x: number, y: number)Moves the canvas to a specific position.centerCanvas()Centers the whiteboard canvas within the viewport.fullScreen()Toggles full-screen mode for the whiteboard.toggleGrid()Enables or disables the background grid for alignment.dispatchBatch(actions: WhiteboardAction[])Dispatches a batch of actions to the whiteboard.
Layer Management
bringToFront(elementOrId: WhiteboardElement | string)Brings the specified element to the front (highest z-index).bringForward(elementOrId: WhiteboardElement | string)Moves the element one layer forward.sendToBack(elementOrId: WhiteboardElement | string)Sends the specified element to the back (lowest z-index).sendBackward(elementOrId: WhiteboardElement | string)Moves the element one layer backward.setZIndex(elementOrId: WhiteboardElement | string, zIndex: number)Sets the exact z-index for an element.getZIndex(elementOrId: WhiteboardElement | string)Returns the current z-index of an element.removeLayer(id: string, mode: 'delete-elements' | 'move-elements' = 'delete-elements')Removes a layer;'move-elements'moves its elements to the layer below instead of deleting them.mergeLayerDown(id: string)Merges a layer into the one below it.beginLayerOpacityEdit(id: string)/endLayerOpacityEdit()Group a live opacity drag into a single undo step.
Layer operations are undoable.
Clipboard Operations
copy()Copies the currently selected elements to the clipboard.cut()Cuts the currently selected elements (copies and removes them).paste()Pastes elements from the clipboard at the current cursor position.duplicate()Duplicates the currently selected elements.
Viewport Control
zoomIn()Increases the zoom level.zoomOut()Decreases the zoom level.setZoom(level: number)Sets the zoom level to a specific value.resetZoom()Resets the zoom level to 100%.pan(deltaX: number, deltaY: number)Pans the canvas by the specified offset.resetPan()Resets the canvas to its original position.
Behaviour Changes
<ng-whiteboard>now shows the built-in editor by default. Add[showEditor]="false"to keep the previous canvas-only rendering.- The default
penTypeis nowPenType.Marker(wasPenType.Pen). Setconfig.penTypetoPenType.Pento keep the previous default. save()output is now cropped to the content bounds with 16px padding (an empty board still exports the canvas box) and never includes editor chrome. ForFormatType.Svgthe vector is downloaded directly and the returned string is the SVG data URL.- JPEG export has a white background.
- Raster exports are limited to 16384px per side and 268,435,456 pixels in total; the scale is reduced to fit.
reorderLayersByIndexindices count from the top layer, as shown in the layers panel.addLayerandsetActiveLayerno longer hide the other layers.removeLayer(id)now deletes the layer's elements by default; pass'move-elements'to keep them. Moved elements are stacked above the target layer's elements when moving down, or below them when moving up.Ctrl/Cmd + Shift + Cno longer copies elements.importDatais a single undo step.importDataFromFilealso opens PNG and SVG images exported withembedBoardData; other images are rejected withThis image has no board data.- Elements without a
layerId(or with an unknown one) belong to the bottom layer for counts, visibility, lock and export. Older boards with orphaned elements now show them on the bottom layer. - The element arrays in
layers()are now derived from each element'slayerId.
Keyboard Shortcuts
The whiteboard supports comprehensive keyboard shortcuts for enhanced productivity:
Selection & Editing
| Shortcut | Action |
|---|---|
Ctrl/Cmd + A |
Select all elements |
Escape |
Clear selection |
Delete / Backspace |
Delete selected elements |
Ctrl/Cmd + C |
Copy selected elements |
Ctrl/Cmd + X |
Cut selected elements |
Ctrl/Cmd + V |
Paste elements |
Ctrl/Cmd + D |
Duplicate selected elements |
Undo/Redo
| Shortcut | Action |
|---|---|
Ctrl/Cmd + Z |
Undo last action |
Ctrl/Cmd + Shift + Z / Ctrl/Cmd + Y |
Redo last undone action |
Layer Management
| Shortcut | Action |
|---|---|
Ctrl/Cmd + Shift + ] |
Bring to front |
Ctrl/Cmd + ] |
Bring forward |
Ctrl/Cmd + Shift + [ |
Send to back |
Ctrl/Cmd + [ |
Send backward |
Tools
| Shortcut | Action |
|---|---|
V |
Select tool |
P |
Pen tool |
L |
Line tool |
R |
Rectangle tool |
E |
Ellipse tool |
A |
Arrow tool |
T |
Text tool |
I |
Image tool |
H |
Hand tool (pan) |
D |
Eraser tool |
Viewport
| Shortcut | Action |
|---|---|
Ctrl/Cmd + + / Ctrl/Cmd + = |
Zoom in |
Ctrl/Cmd + - |
Zoom out |
Ctrl/Cmd + 0 |
Reset zoom (100%) |
Space + Drag |
Pan canvas (when not in hand tool mode) |
Modifiers
| Shortcut | Action |
|---|---|
Shift + Drag |
Constrain proportions (drawing shapes) |
Alt/Option + Drag |
Draw from center (shapes) |
Ctrl/Cmd + Drag |
Duplicate while dragging |
Note:
Ctrlis used on Windows/Linux,Cmd(⌘) is used on macOS.
Context Menu
Right-click on the canvas or elements to access the context menu with quick actions:
Canvas Context Menu
- Paste - Paste copied elements
- Select All - Select all elements on canvas
- Clear Canvas - Remove all elements
Element Context Menu
- Cut - Cut selected element(s)
- Copy - Copy selected element(s)
- Paste - Paste from clipboard
- Duplicate - Create a copy of selected element(s)
- Delete - Remove selected element(s)
- Bring to Front - Move to top layer
- Bring Forward - Move one layer up
- Send to Back - Move to bottom layer
- Send Backward - Move one layer down
The context menu is context-aware and shows relevant options based on the current selection and clipboard state.
Whiteboard Events (Outputs)
The NgWhiteboardComponent emits the following events to notify about changes and interactions.
Lifecycle Events
readyEmitted when the whiteboard is fully initialized and ready for use.destroyedEmitted when the whiteboard is destroyed, allowing for cleanup.
Drawing Events
drawStartTriggered when a user starts drawing on the whiteboard.drawingEmitted continuously while the user is drawing.drawEndTriggered when the user stops drawing.
State & Data Events
undoEmitted when an undo action is performed.redoEmitted when a redo action is performed.clearTriggered when the whiteboard is cleared.dataChangeEmitted when the whiteboard's internal data state changes.saveTriggered when the whiteboard state is saved.
Element Events
elementsAddedEmitted when a new element is added to the whiteboard.elementsUpdatedTriggered when an existing element is modified.elementsSelectedEmitted when an element is selected.elementsDeletedTriggered when an element is removed.
Image Events
imageAddedEmitted when an image is added to the whiteboard.
Configuration & Tool Events
selectedToolChangeTriggered when the active drawing tool is changed.configChangedEmitted when the whiteboard configuration settings are updated.
Contributing
We welcome contributions! Feel free to submit issues, feature requests, or pull requests.
License
This project is licensed under the MIT License.