Interactive Data Grid
This demo showcases the power of LemonadeJS data-grid plugin to create fully reactive, editable tables with built-in features like search, pagination, and real-time data binding.
<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/data-grid/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lemonadejs/data-grid/dist/style.min.css" />
<div id="root"></div>
<script>
function DataGridDemo() {
const self = this;
// Sample data with more fields
self.data = [
{ id: 1, name: "John Doe", email: "john@example.com", role: "Developer", department: "Engineering", salary: "$95,000", status: "Active", joined: "2022-03-15" },
{ id: 2, name: "Jane Smith", email: "jane@example.com", role: "Designer", department: "Design", salary: "$85,000", status: "Active", joined: "2021-08-22" },
{ id: 3, name: "Bob Johnson", email: "bob@example.com", role: "Manager", department: "Operations", salary: "$105,000", status: "Inactive", joined: "2020-01-10" },
{ id: 4, name: "Alice Williams", email: "alice@example.com", role: "Developer", department: "Engineering", salary: "$92,000", status: "Active", joined: "2023-05-18" },
{ id: 5, name: "Charlie Brown", email: "charlie@example.com", role: "QA Engineer", department: "Quality", salary: "$78,000", status: "Active", joined: "2022-11-05" },
{ id: 6, name: "Diana Prince", email: "diana@example.com", role: "Product Owner", department: "Product", salary: "$110,000", status: "Active", joined: "2021-02-14" },
{ id: 7, name: "Eve Martinez", email: "eve@example.com", role: "Developer", department: "Engineering", salary: "$88,000", status: "Inactive", joined: "2023-09-30" },
{ id: 8, name: "Frank Castle", email: "frank@example.com", role: "DevOps", department: "Engineering", salary: "$98,000", status: "Active", joined: "2022-07-12" },
{ id: 9, name: "Grace Lee", email: "grace@example.com", role: "Designer", department: "Design", salary: "$82,000", status: "Active", joined: "2023-01-20" },
{ id: 10, name: "Henry Ford", email: "henry@example.com", role: "Manager", department: "Sales", salary: "$115,000", status: "Active", joined: "2020-06-08" },
];
// Enhanced grid configuration with custom rendering
self.columns = [
{
name: 'id',
title: 'ID',
width: '60px',
align: 'center'
},
{
name: 'name',
title: 'Name',
width: '150px',
align: 'center',
render: function(value) {
return '<strong>' + value + '</strong>';
}
},
{
name: 'email',
title: 'Email',
width: '200px',
align: 'center'
},
{
name: 'role',
title: 'Role',
width: '130px',
align: 'center'
},
{
name: 'department',
title: 'Department',
width: '120px',
align: 'center'
},
{
name: 'salary',
title: 'Salary',
width: '100px',
align: 'center'
},
{
name: 'status',
title: 'Status',
width: '100px',
align: 'center',
render: function(value) {
const color = value === 'Active' ? '#22c55e' : '#ef4444';
return '<span style="color: ' + color + '; font-weight: 600;">' + value + '</span>';
}
},
{
name: 'joined',
title: 'Joined Date',
width: '110px',
align: 'center'
}
];
self.gridRef = null;
self.updateTrigger = 0;
self.onUpdate = function(instance, cell, x, y, value) {
// Force reactivity by updating trigger
self.updateTrigger++;
};
self.addEmployee = function() {
const newId = self.data.length + 1;
self.data = [...self.data, {
id: newId,
name: "New Employee",
email: "new@example.com",
role: "Developer",
department: "Engineering",
salary: "$80,000",
status: "Active",
joined: new Date().toISOString().split('T')[0]
}];
self.updateTrigger++;
};
self.removeSelected = function() {
if (self.data.length > 0) {
self.data = self.data.slice(0, -1);
self.updateTrigger++;
}
};
self.getActiveCount = function() {
return self.data.filter(emp => emp.status === 'Active').length;
};
return `<div style="padding: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<h3 style="margin: 0;">Employee Management System</h3>
<div style="display: flex; gap: 10px;">
<button onclick="self.addEmployee()" class="button primary">Add Employee</button>
<button onclick="self.removeSelected()" class="button">Remove Last</button>
</div>
</div>
<p style="margin: 0 0 16px 0; font-size: 13px; color: #64748b;"><em>💡 Tip: Double-click any cell to edit. Try changing the Status to "Active" or "Inactive"</em></p>
<DataGrid
:ref="self.gridRef"
:data="self.data"
:columns="self.columns"
search="true"
pagination="5"
editable="true"
resizable="true"
:onupdate="self.onUpdate" />
<div style="margin-top: 25px; padding: 20px; background: #f8fafc; border-radius: 8px; display: flex; gap: 30px;">
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Total Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #1e293b;">{{self.updateTrigger >= 0 ? self.data.length : 0}}</p>
</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Active Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #22c55e;">{{self.updateTrigger >= 0 ? self.getActiveCount() : 0}}</p>
</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Inactive Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #ef4444;">{{self.updateTrigger >= 0 ? (self.data.length - self.getActiveCount()) : 0}}</p>
</div>
</div>
</div>`;
}
lemonade.render(DataGridDemo, document.getElementById('root'));
</script>
</html>
import lemonade from 'lemonadejs';
import Datagrid from '@lemonadejs/data-grid';
import '@lemonadejs/data-grid/dist/style.min.css';
export default function DataGridDemo() {
const self = this;
// Sample data with more fields
self.data = [
{ id: 1, name: "John Doe", email: "john@example.com", role: "Developer", department: "Engineering", salary: "$95,000", status: "Active", joined: "2022-03-15" },
{ id: 2, name: "Jane Smith", email: "jane@example.com", role: "Designer", department: "Design", salary: "$85,000", status: "Active", joined: "2021-08-22" },
{ id: 3, name: "Bob Johnson", email: "bob@example.com", role: "Manager", department: "Operations", salary: "$105,000", status: "Inactive", joined: "2020-01-10" },
{ id: 4, name: "Alice Williams", email: "alice@example.com", role: "Developer", department: "Engineering", salary: "$92,000", status: "Active", joined: "2023-05-18" },
{ id: 5, name: "Charlie Brown", email: "charlie@example.com", role: "QA Engineer", department: "Quality", salary: "$78,000", status: "Active", joined: "2022-11-05" },
{ id: 6, name: "Diana Prince", email: "diana@example.com", role: "Product Owner", department: "Product", salary: "$110,000", status: "Active", joined: "2021-02-14" },
{ id: 7, name: "Eve Martinez", email: "eve@example.com", role: "Developer", department: "Engineering", salary: "$88,000", status: "Inactive", joined: "2023-09-30" },
{ id: 8, name: "Frank Castle", email: "frank@example.com", role: "DevOps", department: "Engineering", salary: "$98,000", status: "Active", joined: "2022-07-12" },
{ id: 9, name: "Grace Lee", email: "grace@example.com", role: "Designer", department: "Design", salary: "$82,000", status: "Active", joined: "2023-01-20" },
{ id: 10, name: "Henry Ford", email: "henry@example.com", role: "Manager", department: "Sales", salary: "$115,000", status: "Active", joined: "2020-06-08" },
];
// Enhanced grid configuration
self.columns = [
{ name: 'id', title: 'ID', width: '60px', align: 'center' },
{ name: 'name', title: 'Name', width: '150px', align: 'center', render: (v) => `<strong>${v}</strong>` },
{ name: 'email', title: 'Email', width: '200px', align: 'center' },
{ name: 'role', title: 'Role', width: '130px', align: 'center' },
{ name: 'department', title: 'Department', width: '120px', align: 'center' },
{ name: 'salary', title: 'Salary', width: '100px', align: 'center' },
{
name: 'status',
title: 'Status',
width: '100px',
align: 'center',
render: (v) => {
const color = v === 'Active' ? '#22c55e' : '#ef4444';
return `<span style="color: ${color}; font-weight: 600;">${v}</span>`;
}
},
{ name: 'joined', title: 'Joined Date', width: '110px', align: 'center' }
];
self.updateTrigger = 0;
self.onUpdate = (instance, cell, x, y, value) => {
self.updateTrigger++;
};
self.addEmployee = () => {
self.data = [...self.data, {
id: self.data.length + 1,
name: "New Employee",
email: "new@example.com",
role: "Developer",
department: "Engineering",
salary: "$80,000",
status: "Active",
joined: new Date().toISOString().split('T')[0]
}];
self.updateTrigger++;
};
self.removeSelected = () => {
if (self.data.length > 0) {
self.data = self.data.slice(0, -1);
self.updateTrigger++;
}
};
self.getActiveCount = () => self.data.filter(emp => emp.status === 'Active').length;
return `<div style="padding: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<h3 style="margin: 0;">Employee Management System</h3>
<div style="display: flex; gap: 10px;">
<button onclick="self.addEmployee()" class="button primary">Add Employee</button>
<button onclick="self.removeSelected()" class="button">Remove Last</button>
</div>
</div>
<p style="margin: 0 0 16px 0; font-size: 13px; color: #64748b;"><em>💡 Tip: Double-click any cell to edit. Try changing the Status to "Active" or "Inactive"</em></p>
<DataGrid :data="self.data" :columns="self.columns" search="true" pagination="5" editable="true" resizable="true" :onupdate="self.onUpdate" />
<div style="margin-top: 25px; padding: 20px; background: #f8fafc; border-radius: 8px; display: flex; gap: 30px;">
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Total Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #1e293b;">{{self.updateTrigger >= 0 ? self.data.length : 0}}</p>
</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Active Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #22c55e;">{{self.updateTrigger >= 0 ? self.getActiveCount() : 0}}</p>
</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b;">Inactive Employees</h4>
<p style="margin: 0; font-size: 24px; font-weight: 700; color: #ef4444;">{{self.updateTrigger >= 0 ? (self.data.length - self.getActiveCount()) : 0}}</p>
</div>
</div>
</div>`;
}
import React, { useState } from 'react';
import { DataGrid } from '@lemonadejs/data-grid/react';
import '@lemonadejs/data-grid/dist/style.min.css';
export default function DataGridDemo() {
const [data, setData] = useState([
{ id: 1, name: "John Doe", email: "john@example.com", role: "Developer", department: "Engineering", salary: "$95,000", status: "Active", joined: "2022-03-15" },
{ id: 2, name: "Jane Smith", email: "jane@example.com", role: "Designer", department: "Design", salary: "$85,000", status: "Active", joined: "2021-08-22" },
{ id: 3, name: "Bob Johnson", email: "bob@example.com", role: "Manager", department: "Operations", salary: "$105,000", status: "Inactive", joined: "2020-01-10" },
{ id: 4, name: "Alice Williams", email: "alice@example.com", role: "Developer", department: "Engineering", salary: "$92,000", status: "Active", joined: "2023-05-18" },
{ id: 5, name: "Charlie Brown", email: "charlie@example.com", role: "QA Engineer", department: "Quality", salary: "$78,000", status: "Active", joined: "2022-11-05" },
{ id: 6, name: "Diana Prince", email: "diana@example.com", role: "Product Owner", department: "Product", salary: "$110,000", status: "Active", joined: "2021-02-14" },
{ id: 7, name: "Eve Martinez", email: "eve@example.com", role: "Developer", department: "Engineering", salary: "$88,000", status: "Inactive", joined: "2023-09-30" },
{ id: 8, name: "Frank Castle", email: "frank@example.com", role: "DevOps", department: "Engineering", salary: "$98,000", status: "Active", joined: "2022-07-12" },
{ id: 9, name: "Grace Lee", email: "grace@example.com", role: "Designer", department: "Design", salary: "$82,000", status: "Active", joined: "2023-01-20" },
{ id: 10, name: "Henry Ford", email: "henry@example.com", role: "Manager", department: "Sales", salary: "$115,000", status: "Active", joined: "2020-06-08" },
]);
const columns = [
{ name: 'id', title: 'ID', width: '60px', align: 'center' },
{ name: 'name', title: 'Name', width: '150px', align: 'center', render: (v) => `<strong>${v}</strong>` },
{ name: 'email', title: 'Email', width: '200px', align: 'center' },
{ name: 'role', title: 'Role', width: '130px', align: 'center' },
{ name: 'department', title: 'Department', width: '120px', align: 'center' },
{ name: 'salary', title: 'Salary', width: '100px', align: 'center' },
{
name: 'status',
title: 'Status',
width: '100px',
align: 'center',
render: (v) => {
const color = v === 'Active' ? '#22c55e' : '#ef4444';
return `<span style="color: ${color}; font-weight: 600;">${v}</span>`;
}
},
{ name: 'joined', title: 'Joined Date', width: '110px', align: 'center' }
];
const onUpdate = (instance, cell, x, y, value) => {
setData([...data]);
};
const addEmployee = () => {
setData([...data, {
id: data.length + 1,
name: "New Employee",
email: "new@example.com",
role: "Developer",
department: "Engineering",
salary: "$80,000",
status: "Active",
joined: new Date().toISOString().split('T')[0]
}]);
};
const removeSelected = () => {
if (data.length > 0) {
setData(data.slice(0, -1));
}
};
const getActiveCount = () => data.filter(emp => emp.status === 'Active').length;
return (
<div style={{ padding: '20px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
<h3 style={{ margin: 0 }}>Employee Management System</h3>
<div style={{ display: 'flex', gap: '10px' }}>
<button onClick={addEmployee} className="button primary">Add Employee</button>
<button onClick={removeSelected} className="button">Remove Last</button>
</div>
</div>
<p style={{ margin: '0 0 16px 0', fontSize: '13px', color: '#64748b' }}><em>💡 Tip: Double-click any cell to edit. Try changing the Status to "Active" or "Inactive"</em></p>
<DataGrid
data={data}
columns={columns}
search={true}
pagination={5}
editable={true}
resizable={true}
onupdate={onUpdate}
/>
<div style={{ marginTop: '25px', padding: '20px', background: '#f8fafc', borderRadius: '8px', display: 'flex', gap: '30px' }}>
<div>
<h4 style={{ margin: '0 0 8px 0', fontSize: '14px', color: '#64748b' }}>Total Employees</h4>
<p style={{ margin: 0, fontSize: '24px', fontWeight: 700, color: '#1e293b' }}>{data.length}</p>
</div>
<div>
<h4 style={{ margin: '0 0 8px 0', fontSize: '14px', color: '#64748b' }}>Active Employees</h4>
<p style={{ margin: 0, fontSize: '24px', fontWeight: 700, color: '#22c55e' }}>{getActiveCount()}</p>
</div>
<div>
<h4 style={{ margin: '0 0 8px 0', fontSize: '14px', color: '#64748b' }}>Inactive Employees</h4>
<p style={{ margin: 0, fontSize: '24px', fontWeight: 700, color: '#ef4444' }}>{data.length - getActiveCount()}</p>
</div>
</div>
</div>
);
}
<template>
<div>
<h3>Employee Management</h3>
<DataGrid
:data="data"
:columns="columns"
:search="true"
:pagination="4"
/>
<div style="margin-top: 20px;">
<h4>Live Data Preview:</h4>
<p>Total Employees: {{ data.length }}</p>
</div>
</div>
</template>
<script>
import { DataGrid } from '@lemonadejs/data-grid/vue';
import '@lemonadejs/data-grid/dist/style.min.css';
export default {
name: 'DataGridDemo',
components: {
DataGrid
},
data() {
return {
data: [
{ name: "John Doe", email: "john@example.com", role: "Developer", status: "Active" },
{ name: "Jane Smith", email: "jane@example.com", role: "Designer", status: "Active" },
{ name: "Bob Johnson", email: "bob@example.com", role: "Manager", status: "Inactive" },
{ name: "Alice Williams", email: "alice@example.com", role: "Developer", status: "Active" },
{ name: "Charlie Brown", email: "charlie@example.com", role: "QA Engineer", status: "Active" },
{ name: "Diana Prince", email: "diana@example.com", role: "Product Owner", status: "Active" },
{ name: "Eve Martinez", email: "eve@example.com", role: "Developer", status: "Inactive" },
{ name: "Frank Castle", email: "frank@example.com", role: "DevOps", status: "Active" },
],
columns: [
{ name: 'name', title: 'Name', width: '150px' },
{ name: 'email', title: 'Email', width: '200px' },
{ name: 'role', title: 'Role', width: '150px' },
{ name: 'status', title: 'Status', width: '100px' },
]
}
}
}
</script>