webdevpuneet.com

Fabric.js Sticky Note Board — Draggable Canvas Notes Snippet

Fabric.js Sticky Note Board · Dashboards · Plain HTML, CSS & JS · Live preview

CategoryDashboards

Copy & paste

Source Code

Requires
<div class="fsb-stage">
  <div class="fsb-head">
    <span class="fsb-tag">Fabric.js · canvas objects</span>
    <h2>Sticky Note Board</h2>
    <p>Add a note, drag it anywhere, resize it by its corner handles, double-click the text to edit.</p>
  </div>
  <div class="fsb-toolbar">
    <button class="fsb-btn" id="fsbAdd">+ Add note</button>
    <button class="fsb-btn fsb-btn-ghost" id="fsbClear">Clear board</button>
  </div>
  <div class="fsb-board">
    <canvas id="fsbCanvas"></canvas>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Rect + IText grouping
Each note is two Fabric objects combined into one draggable fabric.Group.
Random pastel palette
A small color array picked with Math.random keeps notes visually distinct.
subTargetCheck hit-testing
Lets a double-click identify the text child inside the group.
Ungroup-edit-regroup pattern
The standard Fabric.js approach for editable text inside a draggable shape.
Drop-shadow cards
A shadow config on the rect lifts notes off the board visually.
Built-in resize handles
hasControls gives every note native corner and edge resize handles.
Auto-select on add
A freshly added note is immediately the active object.
One-click board clear
canvas.clear() with a background reset in one handler.

About this UI Snippet

Fabric.js Sticky Note Board — Grouping Shapes and Text Together

Screenshot of the Fabric.js Sticky Note Board snippet rendered live

A sticky note is conceptually one object — a colored card with text on it — but on an HTML5 <canvas> there is no such thing as a "note" primitive. Fabric.js solves this with fabric.Group, which wraps several individually-drawn objects so they behave as one for selection, dragging, and resizing, while still letting you reach inside for the text.

Building a note as a group

Each note is a fabric.Rect (the card) plus a fabric.IText (the editable label), constructed with coordinates relative to (0, 0) and then handed to new fabric.Group([rect, text], { left, top }). Fabric repositions the whole group's bounding box to left/top and keeps the two children's relative offsets intact. Drag the group and both children move together; grab a corner handle and hasControls: true (the default) lets you scale the whole card including its text proportionally.

Reaching inside a group: subTargetCheck

By default, clicking anywhere on a Fabric group selects the *group*, not the object you clicked. Setting subTargetCheck: true makes Fabric also hit-test the children and report which one you actually clicked, via opt.subTargets on interaction events. This snippet listens for mousedblclick on the group and checks opt.subTargets[0] — if it's the i-text child, that's the signal to start editing.

Editing text inside a group: ungroup, edit, regroup

Fabric's IText supports rich in-place editing (enterEditing(), a blinking cursor, text selection) but only when it is a canvas object in its own right, not while it's locked inside a group's coordinate space. So on double-click this snippet:

1. Removes the group from the canvas and adds just the text object back, positioned at the group's former on-canvas location. 2. Calls target.enterEditing() and target.selectAll() so the user can start typing immediately. 3. Listens for the text object's editing:exited event — fired when the user clicks away or presses Escape — and at that point rebuilds a fresh Rect + IText pair with the (possibly changed) text, regroups them, and adds the group back.

This ungroup-edit-regroup dance is the standard Fabric.js pattern for editable text inside a draggable shape, because Fabric does not support editing a text object *while* it remains a group child.

Random pastel fills

Each new note picks a color from a small PASTELS array with Math.random(), and a drop shadow (shadow: { color, blur, offsetX, offsetY }) is applied to the rect so the notes visually lift off the corkboard-colored canvas background.

Clearing the board

canvas.clear() removes every object but also resets backgroundColor, so the click handler re-sets it immediately after clearing to keep the board's paper tone.

Step by step

How to Use

  1. 1
    Add the Fabric.js CDNInclude fabric.min.js from the CDN panel — it attaches a global fabric object.
  2. 2
    Paste HTML, CSS, and JSA canvas board renders with two starter sticky notes.
  3. 3
    Click "+ Add note"A new pastel note appears, offset from the last one, and is auto-selected.
  4. 4
    Drag and resizeGrab a note to move it, or its corner handles to scale it.
  5. 5
    Double-click the textThe note ungroups its text for in-place editing, then regroups on blur.
  6. 6
    Clear the boardThe Clear board button empties the canvas and resets the background.

Real-world uses

Common Use Cases

Brainstorm boards
Build a lightweight canvas idea board where each note is a Rect and an IText combined into one draggable fabric.Group.
Kanban-style planning
Add freeform notes that can be dragged into columns, resized, and edited in place with a double-click.
Retro and standup boards
Run team retrospectives with colour-coded notes picked from a small random pastel palette, so the board looks lively.
Teaching canvas grouping
Use it as a concrete reference for fabric.Group, and for the ungroup, edit and regroup pattern behind editable text inside groups.
Whiteboard prototypes
Start a richer collaborative whiteboard from this base, where subTargetCheck lets a double-click identify the text child inside the group.

Got questions?

Frequently Asked Questions

Fabric groups objects for interaction purposes, not just visuals — a fabric.Group gives the pair one shared selection box, one set of resize handles, and one drag gesture. Without grouping, dragging the rect would leave the text behind.

Fabric.IText\u2019s editing mode (cursor, selection, keyboard input) operates in the object\u2019s own coordinate space and is not supported while the object is a group child, whose coordinates are relative to the group. The snippet temporarily removes the text from the group, edits it standalone, then rebuilds the group on editing:exited.

By default Fabric groups treat clicks as hitting the group as a whole. Setting subTargetCheck: true makes Fabric also hit-test each child and report it via opt.subTargets in interaction event handlers, which is how the double-click handler knows whether the text specifically was clicked.

Listen for the group\u2019s object:moving event and round event.target.left / event.target.top to the nearest grid increment before Fabric renders the frame, similar to the snapping pattern used in the Konva drag-and-snap snippet.

Call canvas.toJSON() to serialize every object (including groups) to a plain object, store it, and later restore with canvas.loadFromJSON(json, canvas.renderAll.bind(canvas)).

requestRenderAll batches multiple render requests within the same animation frame into a single repaint, which avoids redundant redraws when several object properties change in quick succession, such as during the group-rebuild sequence.