@coderegtech/jsonify-ws
v1.5.7
Published
Real-time JSON sync over WebSocket using Socket.IO. Drop-in React hook + Node server for collaborative JSON editing.
Maintainers
Readme
jsonify-ws
Real-time JSON synchronization over WebSocket using Socket.IO. Provides React hooks for the client, a data-copy attribute system for inline content editing, and a ready-to-run sync server.
Install
npm install @coderegtech/jsonify-ws socket.io-clientEnvironment Variables
WebSocket URL
Set WSL_URL to your WebSocket server URL:
# .env (Vite)
VITE_WSL_URL=http://localhost:4000
# .env (CRA / Next.js)
REACT_APP_WSL_URL=http://localhost:4000
# Or set directly
WSL_URL=http://localhost:4000If not set, defaults to
http://localhost:4000.
Edit Mode
Set EDIT_MODE=true to enable inline content editing. When not set or false, edit features are disabled (no toggle button, no contentEditable).
# .env (Vite)
VITE_EDIT_MODE=true
# .env (CRA / Next.js)
REACT_APP_EDIT_MODE=true
# Or set directly
EDIT_MODE=trueNote: Edit mode is disabled by default. Set
EDIT_MODE=trueonly in environments where you want editing capabilities.
Quick Start
1. Start the server
# Option A: CLI
npx jsonify-ws-server
# Option B: Programmaticimport { createJsonifyServer } from "@coderegtech/jsonify-ws/server";
createJsonifyServer(4000); // port, cors origin2. Use the useJsonify() hook
import { useJsonify } from "@coderegtech/jsonify-ws";
function App() {
const j = useJsonify({
autoConnect: true,
initialData: { home: { title: "Hello World", subtitle: "Edit me!" } },
});
return (
<div>
<p>Status: {j.status}</p>
<button onClick={j.toggleEditMode}>
{j.editMode ? "✅ Editing" : "✏️ Edit Mode"}
</button>
<h1 data-copy="home.title">{j.data.home?.title}</h1>
<p data-copy="home.subtitle">{j.data.home?.subtitle}</p>
</div>
);
}API
useJsonify(options?)
The primary hook — combines WebSocket sync with data-copy attribute scanning and contentEditable.
| Option | Type | Default | Description |
| ----------------------- | --------------------------- | ----------------- | ----------------------------------------------------------- |
| url | string | WSL_URL env | WebSocket server URL |
| autoConnect | boolean | false | Connect on mount |
| initialData | Record<string, JsonValue> | {} | Initial JSON state |
| reconnectionDelay | number | 3000 | Reconnection delay (ms) |
| onSync | (data) => void | — | Callback on remote data received |
| onStatusChange | (status) => void | — | Callback on connection status change |
| onError | (error) => void | — | Callback on connection error |
| targetDocument | Document | window.document | Target document for data-copy scan |
| injectToggle | boolean | EDIT_MODE env | Auto-inject floating edit button (only if EDIT_MODE=true) |
| injectStatusIndicator | boolean | false | Auto-inject WS status indicator (bottom-left) |
Returns:
| Property | Type | Description |
| ---------------- | --------------------------- | ------------------------------ |
| data | Record<string, JsonValue> | Current synced JSON data |
| setData | (data) => void | Update all data (broadcasts) |
| setPath | (path, value) => void | Update a single dot-path |
| status | WsStatus | Connection status |
| connect | (url?) => void | Connect to server |
| disconnect | () => void | Disconnect from server |
| url | string | Resolved WebSocket URL |
| editMode | boolean | Whether edit mode is active |
| toggleEditMode | () => void | Toggle edit mode on/off |
| setEditMode | (active) => void | Set edit mode explicitly |
| elements | DataCopyElement[] | Scanned data-copy elements |
| rescan | () => void | Re-scan for data-copy elements |
useJsonifyWs(options?)
Lower-level hook — WebSocket sync only (no data-copy support).
| Option | Type | Default | Description |
| ------------------- | ---------------------------- | ------------- | ------------------------------------ |
| url | string | WSL_URL env | WebSocket server URL |
| autoConnect | boolean | false | Connect on mount |
| initialData | JsonValue | {} | Initial JSON state |
| reconnectionDelay | number | 3000 | Reconnection delay (ms) |
| onSync | (data: JsonValue) => void | — | Callback on remote data received |
| onStatusChange | (status: WsStatus) => void | — | Callback on connection status change |
| onError | (error: Error) => void | — | Callback on connection error |
Returns:
| Property | Type | Description |
| ------------ | --------------------------- | ----------------------------------------------- |
| data | JsonValue | Current synced JSON data |
| setData | (data: JsonValue) => void | Update data (broadcasts) |
| status | WsStatus | "disconnected" \| "connecting" \| "connected" |
| connect | (url?: string) => void | Connect to server |
| disconnect | () => void | Disconnect from server |
| url | string | Resolved WebSocket URL |
createJsonifyServer(port?, corsOrigin?)
Creates a Socket.IO server that broadcasts JSON updates between clients.
import { createJsonifyServer } from "@coderegtech/jsonify-ws/server";
const io = createJsonifyServer(4000, "*");data-copy Attribute System
Add data-copy attributes to any HTML element to map it to a JSON path:
<h1 data-copy="home.hero.title">Welcome</h1>
<p data-copy="home.hero.subtitle">This is editable</p>
<span data-copy="footer.copyright">© 2026</span>When Edit Mode is activated:
- Elements with
data-copyget a dashed outline and becomecontentEditable - Text changes are synced to the JSON data in real-time
- JSON changes (from other clients) update the element text automatically
- A floating "✏️ Edit Mode" button appears (configurable via
injectToggle)
WebSocket Status Indicator
Enable injectStatusIndicator to show a real-time connection status badge:
const j = useJsonify({
autoConnect: true,
injectStatusIndicator: true, // Shows status in bottom-left corner
});The indicator displays:
- 🔴 Red — Disconnected
- 🟡 Yellow (pulsing) — Connecting
- 🟢 Green — Connected
Standalone utilities
import {
scanDataCopyElements,
enableEditMode,
disableEditMode,
syncElementsFromData,
getByPath,
setByPath,
injectEditToggle,
injectWsStatusIndicator,
isEditModeEnabled,
} from "@coderegtech/jsonify-ws";
// Check if EDIT_MODE env var is enabled
if (isEditModeEnabled()) {
console.log("Edit mode is enabled!");
}
// Scan for elements
const elements = scanDataCopyElements(document);
// Enable editing
enableEditMode(elements);
// Sync JSON data to elements
syncElementsFromData(elements, { home: { title: "Updated!" } });
// Path utilities
const val = getByPath({ a: { b: "hello" } }, "a.b"); // "hello"
const updated = setByPath({ a: { b: "hello" } }, "a.b", "world"); // { a: { b: "world" } }
// Inject floating edit toggle button
const cleanupToggle = injectEditToggle(document, (active) => {
console.log("Edit mode:", active);
});
// Inject WebSocket status indicator
const { cleanup, updateStatus } = injectWsStatusIndicator(document);
updateStatus("connected"); // "disconnected" | "connecting" | "connected"How It Works
- Client connects and pushes its current JSON state
- Server stores latest state and syncs to all other clients
- Any
setData()orsetPath()call broadcasts the update to all peers - New clients receive the latest state on connect
data-copyelements are scanned and mapped to JSON paths- In edit mode, contentEditable changes are captured and synced in real-time
License
MIT
