Codync
A free, open-source 1:1 alternative to Grok Bot and Muse. Message Claude Code, Codex, Cursor and 40+ coding agents as persistent bots from your iPhone, Mac or Linux desktop. Group chats, threads, appr
EzyTables is a minimalist data table library for JavaScript. It is designed to provide developers with a simple and intuitive way to create, manage, and manipulate data tables in their applications.
Developer toolsTypeScript · HTMLGitHub @RA9OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Simplify your data management with effortless ease. Experience the power of simplicity, allowing you to organize, analyze, and visualize your data with intuitive features and a clean interface.
Taken from the repository README
Loading the full README.
Read the full README ↗A minimalistic, zero-dependency JavaScript/TypeScript library for creating reactive data tables with built-in sorting, searching, and pagination.
table.data (push, splice, sort, ...) and the table updates automaticallynpm install ezytables
Or use via CDN:
<script type="module" src="https://esm.sh/ezytables"></script>
import { EzyTables } from "ezytables";
const data = [
{ name: "Alice", email: "[email protected]", role: "Admin" },
{ name: "Bob", email: "[email protected]", role: "User" },
{ name: "Charlie", email: "[email protected]", role: "Moderator" },
];
const table = new EzyTables({
data,
clientEnabled: true,
client: { perPage: 10 },
renderFunction: pageData => {
const tbody = document.querySelector("#myTable tbody");
tbody.innerHTML = "";
pageData.forEach(item => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${item.name}</td>
<td>${item.email}</td>
<td>${item.role}</td>
`;
tbody.appendChild(row);
});
},
});
// Search
document.querySelector("#search").addEventListener("input", e => {
table.setSearchDebounced(e.target.value);
});
// Pagination
document
.querySelector("#prev")
.addEventListener("click", () => table.prevPage());
document
.querySelector("#next")
.addEventListener("click", () => table.nextPage());
Point EzyTables at an existing HTML table and it handles everything:
import { EzyTables } from "ezytables";
const table = new EzyTables({
target: "#myTable",
data: myData,
classes: {
container: "shadow rounded-lg p-4",
table: {
container: "min-w-full",
thead: { th: "px-3 py-3 text-left text-sm font-semibold" },
tbody: { td: "px-3 py-4 text-sm" },
},
},
});
| Method | Returns | Description |
|---|---|---|
new EzyTables(options) | EasyTables | Create a new table instance |
setSearchDebounced(query) | void | Search with 300ms debounce |
sortData(field, order?) | void | Sort by field ("asc" or "desc") |
nextPage() | void | Go to next page |
prevPage() | void | Go to previous page |
goToPage(page) | void | Jump to a specific page |
getCurrentPage() | number | Get current page number |
getTotalPages() | number | Get total page count |
getShowingInfo() | string | Get display info (e.g., "Showing 1 to 10 of 50 items") |
setPerPage(n) | void | Change items per page |
registerPlugin(plugin) | void | Register a data transform plugin |
setData(data) | void | Replace the data source |
getRawData() | any[] | Get a copy of the raw data |
data (property) | any[] | The live, reactive data array (see below) |
destroy() | void | Clean up and remove the table |
table.data is the live data array. Changing it re-renders the table and
calls onDataChange. Several changes made together trigger a single
re-render:
table.data.push({ name: "Dana", email: "[email protected]" });
table.data.splice(0, 1); // remove the first row
table.data.sort((a, b) => a.name.localeCompare(b.name));
table.data[0] = { ...table.data[0], name: "Alicia" }; // replace a row
Only changes to the array itself are observed. The array you passed in as
data is not watched, and editing a property of a row object
(table.data[0].name = "x") does not trigger an update, so replace the row
instead. In server mode the data is replaced on every fetch, so use the
server API to change it.
Transform cell data before rendering:
const datePlugin = {
name: "dateFormat",
field: "date",
transform: value => {
return new Date(value).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
},
};
const table = new EzyTables({
data: myData,
plugins: [datePlugin],
target: "#myTable",
sanitize: true, // default: sanitize plugin HTML before inserting it
});
[!WARNING] Plugin
transform()results are inserted into the cell as HTML, not text. EzyTables sanitizes plugin output by default before assigning it toinnerHTML. Setsanitize: falseonly when the returned HTML is fully trusted.
The built-in sanitizer:
<script>, <iframe>, <object>, <embed>, <link>, <meta>,
<style> and <base>, plus SVG animation elements (<animate>, <set>,
<animateMotion>, <animateTransform>)on*), style and srcdoc attributeshttp:, https:, mailto: and tel: URLs in
href, src, xlink:href, action and formaction, and removes any other
scheme (such as javascript: or data:) and protocol-relative // URLsBecause inline style attributes are removed, plugins that style their output
should use classes instead (or set sanitize: false for trusted HTML).
Column labels passed in through the columns option are rendered as plain
text, so they are safe to build from user or API data. When EzyTables reads
the columns from an existing table's <th> elements, those labels keep their
HTML, since that markup is already part of your page.
interface EasyTablesOptions {
clientEnabled?: boolean; // Use client-side data (default: true, or false when server.api_url is set)
data?: any[]; // Data source array
target?: string; // CSS selector for existing table
renderFunction?: (data) => void; // Custom render callback
client?: {
limit: number;
perPage?: number; // Items per page (default: 10)
};
server?: {
api_url: string;
headers?: Record<string, string>;
limit: number;
page: number;
dataNames: string; // Dot-separated path to the rows in the response (e.g. "data.items")
};
columns?: Column[];
classes?: Classes; // CSS class overrides
plugins?: Plugin[]; // Data transform plugins
hideDetails?: {
header?: boolean; // Hide search/per-page controls
footer?: boolean; // Hide pagination footer
};
perPageOptions?: number[]; // Custom per-page dropdown options (default: [5, 10, 25, 50, 100])
onPageChange?: (page: number, totalPages: number) => void;
onSearch?: (query: string, resultCount: number) => void;
onSort?: (field: string, order: "asc" | "desc") => void;
onDataChange?: (newData: any[]) => void;
sanitize?: boolean; // Sanitize plugin transform HTML before assigning innerHTML (default: true)
}
# Install dependencies
npm install
# Start dev server
npm run dev
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build for production
npm run build
See CONTRIBUTING.md for guidelines.