Framework-agnostic web component for boolean matrices
edit and display 2D boolean arrays
with interactive cell selection
edit and display 2D boolean arrays
with interactive cell selection

Tip
Example Sources are under ./examples/
- Web Component:
<bit-grid>
for 2D boolean matrices - Zero-deps ESM: single-file module, framework-agnostic
- Selection: click + drag ranges with debounced updates
- Events:
dataChange
event with 2D boolean array - API:
update({ data, rowLabels, colLabels, onChange, debounceMs })
- Theming: CSS custom properties for colors and spacing
- Examples: Vanilla, React, Vue, Angular, CDN
npm install bit-grid-component
<!DOCTYPE html>
<html>
<head>
<script type="module">import 'bit-grid-component'</script>
</head>
<body>
<bit-grid></bit-grid>
<script>
const grid = document.querySelector('bit-grid');
grid.addEventListener('dataChange', (e) => {
console.log('Data changed:', e.detail);
});
</script>
</body>
</html>
<bit-grid></bit-grid>
<script>
const grid = document.querySelector('bit-grid');
grid.update({
data: Array(7).fill(null).map(() => Array(24).fill(false)),
rowLabels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
colLabels: Array.from({length: 24}, (_, i) => `${i}:00`)
});
</script>
import 'bit-grid-component';
import BitGrid from 'bit-grid-component';
const grid = new BitGrid({
data: Array(31).fill(null).map(() => Array(24).fill(false)),
rowLabels: Array.from({length: 31}, (_, i) => `Day ${i + 1}`),
colLabels: Array.from({length: 24}, (_, i) => `${i}h`)
});
// ⚠️ Must append to DOM
document.getElementById('container').appendChild(grid);
const grid = new BitGrid({
data: boolean[][], // Optional: 2D boolean array
rowLabels: string[], // Optional: Array of row labels
colLabels: string[], // Optional: Array of column labels
onChange: function, // Optional: Callback for data changes
debounceMs: number // Optional: Debounce delay (default: 100ms)
});
Inference Priority:
- If both
rowLabels
andcolLabels
provided → data generated automatically - If
data
provided → labels generated if not provided - Default → 5x5 grid with auto-generated labels
// Get current data
const data = grid.getData();
// Update data and labels (infers dimensions)
grid.update({ data: newData, rowLabels: [...], colLabels: [...] });
// Convenience methods
grid.setLabels(['Row1', 'Row2'], ['Col1', 'Col2']);
grid.setData(booleanArray);
grid.setCell(row, col, true);
grid.getCell(row, col);
grid.toggleCell(row, col);
grid.fill(false); // Fill all cells with value
// Reset to empty grid
grid.reset();
grid.addEventListener('dataChange', (e) => {
const data = e.detail; // 2D boolean array
console.log('Grid data changed:', data);
});
bit-grid {
--grid-primary: #3b82f6; /* Active cell color */
--grid-bg: #ffffff; /* Background color */
--grid-cell-bg: #f8fafc; /* Cell background */
--grid-text: #1f2937; /* Text color */
--grid-text-muted: #6b7280; /* Muted text color */
--grid-header-bg: #f1f5f9; /* Header background */
--grid-hover-bg: #e2e8f0; /* Hover background */
--grid-selection-bg: rgba(59, 130, 246, 0.25); /* Selection background */
--grid-selection-active-bg: rgba(59, 130, 246, 0.7); /* Active selection */
--grid-cell-size: 28px; /* Cell size */
--grid-header-width: 80px; /* Header width */
--grid-cell-spacing: 4px; /* Cell spacing */
--grid-cell-radius: 8px; /* Cell border radius */
}
<bit-grid></bit-grid>
<script>
const grid = document.querySelector('bit-grid');
// Just provide labels - data auto-generated
grid.update({
rowLabels: Array.from({length: 31}, (_, i) => `Day ${i + 1}`),
colLabels: Array.from({length: 24}, (_, i) => `${i}h`)
});
grid.addEventListener('dataChange', (e) => {
const activeHours = e.detail.flat().filter(cell => cell).length;
console.log(`Active hours: ${activeHours}`);
});
</script>
import 'bit-grid-component';
import { useEffect, useRef } from 'react';
function AttendanceGrid({ data, onDataChange }) {
const gridRef = useRef();
useEffect(() => {
if (gridRef.current) {
// Labels-first approach
gridRef.current.update({
rowLabels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
colLabels: Array.from({length: 24}, (_, i) => `${i}:00`)
});
// Then set data if provided
if (data) {
gridRef.current.setData(data);
}
gridRef.current.addEventListener('dataChange', onDataChange);
}
}, [data, onDataChange]);
return <bit-grid ref={gridRef} />;
}