demo D105
Collaborative presence
Two windows, two cursors, live selections and edits
grid.presence
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>
<div id="grid" style="height: 540px"></div>
<script>
const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
// Presence positions travel as row key plus column id, never an index, so a
// stable key is what lets two people sorting differently still see each
// other on the same records.
rowKey: 'id',
selection: 'multiple',
columns: [
{ field: 'circuit', title: 'Circuit', layout: { width: 200, pin: 'start' } },
{ field: 'region', title: 'Region' },
{ field: 'status', title: 'Status', filter: { type: 'set' } },
{ field: 'bandwidth', title: 'Bandwidth', type: 'number', filter: { type: 'number' } },
{ field: 'charge', title: 'Monthly charge', type: 'number',
format: { style: 'currency', currency: 'GBP' }, filter: { type: 'number' } },
],
presence: {
// Your transport, which the grid does not own: subscribe hands the grid
// each peer's cursor, ranges and edit claim, and publish sends the local
// state back out. Wire these to your own channel (WebSocket, SSE, etc).
provider: {
subscribe(onMessage) {
// Deliver peer states as they arrive, then return an unsubscribe.
return () => {};
},
publish(state) {
// Send the local cursor, selection and edit claim to the other clients.
},
},
me: { id: 'you', name: 'You' },
},
rows, // an array of objects, one per circuit
});
</script>
Showing who else is looking at the same grid
Presence is the layer that turns a shared dataset into a shared workspace: other users’ cursors, active cell, and selection rendered live inside the same JavaScript data grid rather than inferred after the fact from a changed value. A developer reaches for it once two or more people can open the same view at once, most often a shared spreadsheet-style tool, an ops dashboard during an incident, or a review pass where seeing a colleague move to a row matters more than a chat message saying so. Lattice Grid exposes this through grid.presence, which accepts a stream of remote cursor and selection positions keyed by user and renders them as overlays on the existing cell layout, without altering row or column state. Because presence overlays are painted separately from the row virtualisation pass, adding participants does not change what gets measured or redrawn as the grid scrolls: a cursor for a collaborator outside the visible window stays undrawn until scrolling brings their row into view. Each remote cursor carries a user identifier, so colour and label are assigned per person rather than per session, and a reconnecting user keeps that identity rather than appearing as new. The demo runs two windows side by side, each driving grid.presence independently, so edits and selections in one appear in the other as they happen.
How do you show other users’ cursors in a data grid?
Feed a stream of remote positions into grid.presence, keyed by user id, with each entry carrying a cell or range and a display colour or label. Lattice Grid renders these as overlays on top of the existing grid rather than as separate DOM rows, so presence updates do not affect row virtualisation, sorting, or filtering, and a user’s cursor only redraws when their position or the visible window changes.