Build a browser-based whiteboard where a team can add, move, edit, and remove software-design shapes, then save the canvas through a Node.js server. This guide uses React for the interface, Express for the API, and SVG for drawing; start with a small single-user version before adding collaboration.
What You’ll Need
- Node.js LTS and npm installed. Check with
node -vandnpm -v. - Basic familiarity with JavaScript, React components, and HTTP requests.
- A code editor and two terminal windows, one for each development server.
- A modern browser. A database is optional for the first version; this guide stores a board as a JSON file.
Step-by-Step
- Define the first version’s scope. Start with a single board containing rectangles, text labels, and directional connectors. Support adding, selecting, dragging, editing, deleting, and saving shapes. Use stable IDs for every shape and connector. Defer multi-user editing, permissions, and automatic layout until the basic data model works.
- Create the React client. In a terminal, run
npm create vite@latest design-board -- --template react, thencd design-boardandnpm install. Start the client withnpm run dev. Vite prints the local address to open in your browser. Keep the frontend and server in separate folders, or use a workspace if you already know how to manage one. - Set up the Node.js API. From the project’s parent folder, create a server directory, initialize it with
npm init -y, and installexpressandcors. In the server entry file, create an Express app, enable JSON request parsing, and allow requests from your local Vite origin during development. Add a health-check route such asGET /api/healththat returns JSON. Run the server on a separate port, for example 3001. - Agree on a board data shape. Represent a board as a JSON object with an ID, a name, a list of nodes, and a list of connectors. A node can contain an ID, type, x and y coordinates, width, height, text, and optional style settings. A connector should refer to node IDs rather than only storing endpoint coordinates. Validate incoming data on the server: require IDs and supported types, and reject malformed JSON or unreasonable dimensions.
- Build the canvas and toolbar. In React, create a toolbar with buttons for selecting a tool, adding a component, and saving. Render an SVG canvas with a visible background and a clear coordinate system. SVG is useful here because shapes and lines remain crisp at different sizes and can respond to pointer events. Keep board data in React state; render each node from that state rather than manipulating SVG elements directly.
- Add shape creation and selection. When a user chooses a node tool and clicks the canvas, convert the pointer position into canvas coordinates and add a node with a unique ID and sensible default size. Use a distinct selection state so the selected node can show handles or an outline. Provide visible focus styles and accessible names for toolbar buttons; do not rely on color alone to show selection.
- Implement dragging and text editing. On pointer down, record the selected node ID and the pointer’s starting position. During pointer movement, update that node’s coordinates by the movement delta; stop tracking on pointer up or cancellation. Avoid attaching permanent document-wide handlers on every render. Use SVG text or an HTML input overlay for editing, and commit changes when the user confirms or leaves the field.
- Draw connectors between nodes. Let the user choose a connector tool, then select a source and destination node. Store those node IDs in the connector. Calculate line endpoints from the nodes’ positions when rendering, so moving a node keeps its connections attached. Add an arrowhead with an SVG marker if directional relationships are useful, and make connectors selectable for deletion.
- Add save and load routes. Implement routes such as
GET /api/boards/:idandPUT /api/boards/:id. For a prototype, read and write JSON under a server-owned data directory using Node’s file APIs. Do not accept arbitrary file paths from the browser. Make the client’s save action send the complete board as JSON, and show a saving, saved, or error status. Load existing board data when the app starts and handle a missing board with a clear empty-board state. - Test important interactions. Add a few nodes, connect them, move one, edit text, delete an item, and save. Reload the page and check that the saved state returns. Test empty boards, long labels, rapid pointer movement, and failed or interrupted requests. Use browser developer tools to inspect the network request and server terminal to spot API errors.
- Prepare for deployment and growth. Build the client with
npm run buildand serve its output through a hosting setup that also routes API requests to Node. Configure allowed origins for the deployed client rather than leaving broad development CORS settings. A JSON file is suitable only for a small prototype: use a database for dependable multi-board storage. For simultaneous editors, add authentication, permissions, conflict handling, and a real-time protocol such as WebSockets; saving a whole board is not enough to prevent overwrites.
Common Mistakes
- Mixing screen and canvas coordinates: browser zoom, scrolling, or SVG scaling can make clicks land in the wrong place. Convert pointer positions using the SVG’s coordinate transformation rather than assuming CSS pixels equal canvas units.
- Using array positions as IDs: deleting or reordering an item changes its index and can break connectors. Assign stable unique IDs instead.
- Mutating React state: update the changed node immutably and create a new array, or React may not render the change reliably.
- Writing to a shared JSON file without safeguards: concurrent saves can overwrite one another or corrupt data. Keep file storage for a local prototype, and move to a database with appropriate update handling as usage grows.
- Trusting browser input: validate board content on the server, even if the React interface only creates valid shapes.
Tips
- Keep drawing, toolbar controls, node editing, and API calls in separate components or modules as the project grows.
- Use a reducer or a small state-management layer when undo, redo, or many editing actions become difficult to track.
- Debounce autosave if you add it, and show clearly whether changes are still pending. Do not silently treat a failed save as success.
- Make the canvas usable by keyboard where practical, including selection and deletion, and provide labels for controls.
- Keep a version field in saved board data if you expect the format to change; this makes future migrations easier.
Troubleshooting
- The client cannot reach the API: confirm both servers are running, check the API port and request URL, and look for CORS or connection errors in the browser console. Ensure the server allows the exact local client origin.
- The canvas is blank: inspect the React console for rendering errors and confirm the SVG has a nonzero width and height. Check that the board’s node list is an array before mapping over it.
- Shapes jump while dragging: verify that pointer positions and node coordinates use the same SVG coordinate system. Also ensure the starting pointer position is captured once at pointer down.
- Saving fails or changes disappear after reload: inspect the response status and server logs. Check that the server can write to its data directory and that the client handles non-success responses rather than clearing its local state.
- Connectors detach: confirm each connector refers to valid node IDs and that its rendered endpoints are recalculated from current node positions.
Frequently Asked Questions
Why use SVG instead of a canvas element?
SVG makes individual shapes straightforward to select, label, and update in React. A canvas element can perform better for very large drawings, but requires more custom hit-testing and rendering logic.
Can I use this whiteboard for real-time collaboration?
Not with simple whole-board saves alone. Add a real-time server, identify users, and handle simultaneous edits and conflicting changes before inviting multiple editors.
Do I need a database?
No, not for a local prototype. JSON-file storage demonstrates persistence, but a database is a better fit for multiple boards, users, backups, and concurrent updates.
How can I add undo and redo?
Keep a history of board states or reversible actions, and update history when meaningful edits are committed. Avoid recording every pointer-move event as a separate undo step.
How should I support zoom and pan?
Apply a view transform to the SVG and convert pointer coordinates through that transform. Keep node positions in stable board coordinates so zooming does not rewrite the saved layout.
Related
General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.
More in this bed
- Android Enterprise Device Management: How to Choose
- Fix Windows 10 Computer Freezes Randomly
- Enable or Disable Speech Recognition in Windows 10
- iPad Mini Tips: Settings, Shortcuts, and Everyday Use
- Schedule Do Not Disturb in Windows 11 for Work and Sleep
- Fix iPhone Battery Drain on iOS 10: 10 Practical Tips