├── .cursor └── rules │ ├── library-features.mdc │ └── project-overview.mdc ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── app ├── globals.css ├── layout.tsx ├── list │ └── page.tsx └── page.tsx ├── components.json ├── components ├── Card.tsx ├── FilterBar.tsx ├── IndexPage.tsx ├── MultiItemPicker.tsx ├── SingleItemPicker.tsx ├── TableView.tsx ├── mode-toggle.tsx ├── theme-provider.tsx └── ui │ ├── button.tsx │ ├── card.tsx │ ├── checkbox.tsx │ ├── popover.tsx │ ├── select.tsx │ ├── table.tsx │ └── tooltip.tsx ├── data ├── ag-grid.yml ├── angular-ui-grid.yml ├── antv-s2.yml ├── backgrid.yml ├── bryntum-grid.yml ├── canvas-datagrid.yml ├── cheetah-grid.yml ├── clusterize.yml ├── datagridxl.yml ├── datatables.yml ├── devextreme.yml ├── dgrid.yml ├── dhtmlx-grid.yml ├── ember-table.yml ├── fancygrid.yml ├── flexmonster.yml ├── frappe-datatable.yml ├── functional-data-grid.yml ├── glide-data-grid.yml ├── grid-js.yml ├── handsontable.yml ├── ipgrid.yml ├── jqgrid.yml ├── jqwidgets.yml ├── jspreadsheet-ce.yml ├── jspreadsheet-pro.yml ├── jtable.yml ├── kendo-ui-angular.yml ├── kendo-ui-grid.yml ├── kendo-ui-spreadsheet.yml ├── kendo-ui-vue.yml ├── kendoreact-data-grid.yml ├── lemonade-data-grid.yml ├── luckysheet.yml ├── mantine-react-table.yml ├── material-react-table.yml ├── mui-x-datagrid.yml ├── ng-table.yml ├── paramquery.yml ├── react-base-table.yml ├── react-data-grid.yml ├── react-pivot.yml ├── react-spreadsheet-grid.yml ├── react-spreadsheet.yml ├── react-virtualized-pivot.yml ├── react-window.yml ├── revo-grid.yml ├── sencha-ext-angular.yml ├── sencha-ext-gen.yml ├── sencha-ext-react.yml ├── sensei-grid.yml ├── shadcn-data-table.yml ├── shadcn-table.yml ├── slickgrid.yml ├── smart-grid.yml ├── smart-table.yml ├── sou-react-table.yml ├── spreadjs.yml ├── svar-datagrid.yml ├── syncfusion-datagrid.yml ├── tabulator.yml ├── tanstack-table.yml ├── tui-grid.yml ├── visactor-vtable.yml ├── w2ui.yml ├── wijmo-flexgrid.yml └── wijmo-grid.yml ├── lib ├── cache.ts ├── features.ts ├── fetcher.ts ├── frameworks.ts ├── libraries.ts ├── sorting.ts ├── store.ts ├── ui-constants.ts └── utils.ts ├── next.config.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── public ├── favicon.ico ├── favicon.jpg ├── jsgrids.png └── robots.txt └── tsconfig.json /.cursor/rules/library-features.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: *.yml 4 | alwaysApply: false 5 | --- 6 | When editing feature data files in `data/`, *DO NOT* create new features in libraries.ts unless explicitly asked to. Use only the features already available in `features.ts` when describing a library. -------------------------------------------------------------------------------- /.cursor/rules/project-overview.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | --- 7 | description: JSGrids project overview and architecture guide 8 | globs: 9 | - "**/*.ts" 10 | - "**/*.tsx" 11 | - "**/*.yml" 12 | - "**/*.yaml" 13 | alwaysApply: false 14 | --- 15 | 16 | # JSGrids Project Overview 17 | 18 | JSGrids is a curated directory of JavaScript spreadsheet and data grid libraries hosted at https://jsgrids.statico.io/. This is a Next.js application that helps developers discover and compare data grid solutions for their projects. 19 | 20 | ## Project Purpose 21 | 22 | - **Mission**: Maintain the most comprehensive and up-to-date list of JavaScript data grid and spreadsheet libraries 23 | - **Target Audience**: Frontend developers building internal tools, data auditing interfaces, and workflow applications 24 | - **Value Proposition**: Provides current, maintained information where other lists are outdated 25 | 26 | ## Architecture Overview 27 | 28 | ### Tech Stack 29 | - **Framework**: Next.js 15 with App Router and React 19 30 | - **Styling**: Tailwind CSS 4 with shadcn/ui components 31 | - **Language**: TypeScript with strict typing 32 | - **Package Manager**: pnpm 33 | - **Deployment**: Vercel 34 | - **Data**: YAML files for library definitions 35 | 36 | ### Key Directories 37 | 38 | - `app/` - Next.js App Router pages and layouts 39 | - `components/` - React components including shadcn/ui components 40 | - `data/` - YAML files containing library information (60+ libraries) 41 | - `lib/` - Core business logic, data processing, and utilities 42 | - `public/` - Static assets 43 | 44 | ### Data Structure 45 | 46 | Each library is defined in a YAML file in `data/` with the following structure: 47 | - **Metadata**: title, homeUrl, demoUrl, githubRepo, npmPackage, license 48 | - **Business**: revenueModel (Free/Commercial/Freemium) 49 | - **Frameworks**: Support for vanilla JS, React, Angular, Vue 50 | - **Features**: 25+ feature flags (editable, filtering, sorting, virtualization, etc.) 51 | 52 | ### Core Components 53 | 54 | - **IndexPage**: Main listing page with filtering and search 55 | - **Card**: Individual library display component 56 | - **FilterBar**: Multi-faceted filtering interface 57 | - **ItemPickers**: Framework and feature selection components 58 | 59 | ### Key Libraries & Utilities 60 | 61 | - **lib/libraries.ts**: Core data loading and GitHub API integration 62 | - **lib/features.ts**: Feature definitions and categorization 63 | - **lib/frameworks.ts**: Framework definitions 64 | - **lib/store.ts**: Zustand state management for filters 65 | - **lib/fetcher.ts**: GitHub API client with rate limiting 66 | 67 | ## Development Guidelines 68 | 69 | ### Code Style 70 | - Use TypeScript for all new code 71 | - Follow React best practices with hooks and functional components 72 | - Use Tailwind CSS for styling with consistent design tokens 73 | - Implement proper error handling and loading states 74 | 75 | ### Data Management 76 | - Library data is stored in YAML files for easy editing 77 | - GitHub API integration fetches real-time repository statistics 78 | - Zod schemas validate data structure and types 79 | - Caching layer reduces API calls and improves performance 80 | 81 | ### UI/UX Principles 82 | - Mobile-responsive design 83 | - Dark/light theme support via next-themes 84 | - Accessible components using Radix UI primitives 85 | - Fast filtering and search with client-side state management 86 | 87 | ### Performance Considerations 88 | - GitHub API rate limiting with p-throttle 89 | - Efficient data fetching with retry logic 90 | - Optimized bundle size with proper imports 91 | - Static generation where possible 92 | 93 | ## Contributing Workflow 94 | 95 | 1. Library data updates go in `data/*.yml` files 96 | 2. UI changes use shadcn/ui components and Tailwind 97 | 3. All code must pass Prettier formatting 98 | 4. Vercel deployment validates builds automatically 99 | 100 | ## External Dependencies 101 | 102 | - **GitHub API**: For repository statistics and activity data 103 | - **Vercel**: For hosting and deployment 104 | - **shadcn/ui**: For consistent, accessible UI components 105 | - **Lucide React**: For iconography (only shadcn components) 106 | - **react-icons**: For additional icon sets (everywhere else) 107 | 108 | This project serves as a valuable resource for the JavaScript community by maintaining current information about data grid solutions and their capabilities. 109 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | 43 | # jsgrids 44 | .cache -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | npx lint-staged 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | .husky/_/ 3 | .next/ 4 | node_modules/ 5 | out/ 6 | tsconfig.tsbuildinfo 7 | yarn-error.log -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ian Langworth ☠ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jsgrids 2 | 3 | A List of JavaScript Spreadsheet and Data Grid Libraries - https://jsgrids.statico.io/ 4 | 5 | [![GitHub repo](https://img.shields.io/badge/github-repo-green)](https://github.com/statico/jsgrids) [![GitHub contributors](https://img.shields.io/github/contributors/statico/jsgrids)](https://github.com/statico/jsgrids/graphs/contributors) [![GitHub last commit](https://img.shields.io/github/last-commit/statico/jsgrids)](https://github.com/statico/jsgrids/commits/main) [![GitHub branch status](https://img.shields.io/github/checks-status/statico/jsgrids/main)](https://github.com/statico/jsgrids) 6 | 7 | [screenshot of the jsgrids web interface](https://jsgrids.statico.io) 8 | 9 | ## Motivation 10 | 11 | I build a lot of internal tools for data auditing and workflows, and every few months I end up looking for the best data grid or spreadsheet-like library for JavaScript. Other lists and sites are out of date and unmaintained. My goal here is to make the best list for all data grid and spreadsheet libraries for the top JavaScript frontend frameworks ([1](https://2019.stateofjs.com/front-end-frameworks/), [2](https://2019.stateofjs.com/other-tools/)). You're welcome to help! 12 | 13 | ## Contributing 14 | 15 | Pull requests are welcome to help keep this project up to date. Please make sure the Vercel build passes successfully, and please make sure all source is formatted with [Prettier](https://prettier.io/) (there's a git hook that should do it for you anyway). 16 | 17 | ## Development 18 | 19 | 1. Create a [GitHub Personal Access Token](https://github.com/settings/tokens). You don't need to give it any scopes -- it's just to increase the API rate limit. 20 | 1. Make sure you have [Node.js](https://nodejs.org/) version 12.0 or later and the [pnpm package manager](https://pnpm.io/) installed. 21 | 1. Checkout the repo, run `pnpm install` 22 | 1. Run `GITHUB_TOKEN= pnpm dev` 23 | 1. Go to http://localhost:3000/ and bask in the wild splendor that is jsgrids 24 | 25 | Information on each library is in `data/` and is parsed in `lib/libraries.ts`. Enjoy! 26 | 27 | ## Miscellanous 28 | 29 | - jsgrids is hosted on [Vercel](https://vercel.com/) 30 | - This project makes extensive use of [Tailwind CSS](https://tailwindcss.com/), [Next.js](https://nextjs.org/) (with App Router), and [TypeScript](https://www.typescriptlang.org/) 31 | - Icons are from the various icon sets in [react-icons](https://react-icons.github.io/react-icons/) 32 | - The GitHub corner thing is Tim Holman's fancy [GitHub Corners](http://tholman.com/github-corners/) thing 33 | - All library descriptions are adapted from each package's home page 34 | 35 | ## License 36 | 37 | This project is licensed under the [MIT license](https://github.com/statico/jsgrids/blob/master/LICENSE). 38 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @import "tw-animate-css"; 3 | 4 | @custom-variant dark (&:is(.dark *)); 5 | 6 | @theme inline { 7 | --color-background: var(--background); 8 | --color-foreground: var(--foreground); 9 | --font-sans: var(--font-geist-sans); 10 | --font-mono: var(--font-geist-mono); 11 | --color-sidebar-ring: var(--sidebar-ring); 12 | --color-sidebar-border: var(--sidebar-border); 13 | --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 14 | --color-sidebar-accent: var(--sidebar-accent); 15 | --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); 16 | --color-sidebar-primary: var(--sidebar-primary); 17 | --color-sidebar-foreground: var(--sidebar-foreground); 18 | --color-sidebar: var(--sidebar); 19 | --color-chart-5: var(--chart-5); 20 | --color-chart-4: var(--chart-4); 21 | --color-chart-3: var(--chart-3); 22 | --color-chart-2: var(--chart-2); 23 | --color-chart-1: var(--chart-1); 24 | --color-ring: var(--ring); 25 | --color-input: var(--input); 26 | --color-border: var(--border); 27 | --color-destructive: var(--destructive); 28 | --color-accent-foreground: var(--accent-foreground); 29 | --color-accent: var(--accent); 30 | --color-muted-foreground: var(--muted-foreground); 31 | --color-muted: var(--muted); 32 | --color-secondary-foreground: var(--secondary-foreground); 33 | --color-secondary: var(--secondary); 34 | --color-primary-foreground: var(--primary-foreground); 35 | --color-primary: var(--primary); 36 | --color-popover-foreground: var(--popover-foreground); 37 | --color-popover: var(--popover); 38 | --color-card-foreground: var(--card-foreground); 39 | --color-card: var(--card); 40 | --radius-sm: calc(var(--radius) - 4px); 41 | --radius-md: calc(var(--radius) - 2px); 42 | --radius-lg: var(--radius); 43 | --radius-xl: calc(var(--radius) + 4px); 44 | } 45 | 46 | :root { 47 | --radius: 0.625rem; 48 | --background: oklch(1 0 0); 49 | --foreground: oklch(0.129 0.042 264.695); 50 | --card: oklch(1 0 0); 51 | --card-foreground: oklch(0.129 0.042 264.695); 52 | --popover: oklch(1 0 0); 53 | --popover-foreground: oklch(0.129 0.042 264.695); 54 | --primary: oklch(0.208 0.042 265.755); 55 | --primary-foreground: oklch(0.984 0.003 247.858); 56 | --secondary: oklch(0.968 0.007 247.896); 57 | --secondary-foreground: oklch(0.208 0.042 265.755); 58 | --muted: oklch(0.968 0.007 247.896); 59 | --muted-foreground: oklch(0.554 0.046 257.417); 60 | --accent: oklch(0.968 0.007 247.896); 61 | --accent-foreground: oklch(0.208 0.042 265.755); 62 | --destructive: oklch(0.577 0.245 27.325); 63 | --border: oklch(0.929 0.013 255.508); 64 | --input: oklch(0.929 0.013 255.508); 65 | --ring: oklch(0.704 0.04 256.788); 66 | --chart-1: oklch(0.646 0.222 41.116); 67 | --chart-2: oklch(0.6 0.118 184.704); 68 | --chart-3: oklch(0.398 0.07 227.392); 69 | --chart-4: oklch(0.828 0.189 84.429); 70 | --chart-5: oklch(0.769 0.188 70.08); 71 | --sidebar: oklch(0.984 0.003 247.858); 72 | --sidebar-foreground: oklch(0.129 0.042 264.695); 73 | --sidebar-primary: oklch(0.208 0.042 265.755); 74 | --sidebar-primary-foreground: oklch(0.984 0.003 247.858); 75 | --sidebar-accent: oklch(0.968 0.007 247.896); 76 | --sidebar-accent-foreground: oklch(0.208 0.042 265.755); 77 | --sidebar-border: oklch(0.929 0.013 255.508); 78 | --sidebar-ring: oklch(0.704 0.04 256.788); 79 | } 80 | 81 | .dark { 82 | --background: oklch(27.8% 0.033 256.848); 83 | --foreground: oklch(0.984 0.003 247.858); 84 | --card: oklch(0.25 0.02 256.788); 85 | --card-foreground: oklch(0.984 0.003 247.858); 86 | --popover: oklch(0.2 0.02 265.755); 87 | --popover-foreground: oklch(0.984 0.003 247.858); 88 | --primary: oklch(0.929 0.013 255.508); 89 | --primary-foreground: oklch(0.208 0.042 265.755); 90 | --secondary: oklch(0.279 0.041 260.031); 91 | --secondary-foreground: oklch(0.984 0.003 247.858); 92 | --muted: oklch(0.279 0.041 260.031); 93 | --muted-foreground: oklch(0.704 0.04 256.788); 94 | --accent: oklch(0.279 0.041 260.031); 95 | --accent-foreground: oklch(0.984 0.003 247.858); 96 | --destructive: oklch(0.704 0.191 22.216); 97 | --border: oklch(1 0 0 / 10%); 98 | --input: oklch(1 0 0 / 15%); 99 | --ring: oklch(0.551 0.027 264.364); 100 | --chart-1: oklch(0.488 0.243 264.376); 101 | --chart-2: oklch(0.696 0.17 162.48); 102 | --chart-3: oklch(0.769 0.188 70.08); 103 | --chart-4: oklch(0.627 0.265 303.9); 104 | --chart-5: oklch(0.645 0.246 16.439); 105 | --sidebar: oklch(0.208 0.042 265.755); 106 | --sidebar-foreground: oklch(0.984 0.003 247.858); 107 | --sidebar-primary: oklch(0.488 0.243 264.376); 108 | --sidebar-primary-foreground: oklch(0.984 0.003 247.858); 109 | --sidebar-accent: oklch(0.279 0.041 260.031); 110 | --sidebar-accent-foreground: oklch(0.984 0.003 247.858); 111 | --sidebar-border: oklch(1 0 0 / 10%); 112 | --sidebar-ring: oklch(0.551 0.027 264.364); 113 | } 114 | 115 | @layer base { 116 | * { 117 | @apply border-border outline-ring/50; 118 | } 119 | body { 120 | @apply bg-background text-foreground; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Script from "next/script"; 3 | import type { Metadata } from "next"; 4 | import "./globals.css"; 5 | import { TooltipProvider } from "@/components/ui/tooltip"; 6 | import { ThemeProvider } from "@/components/theme-provider"; 7 | 8 | const name = "jsgrids"; 9 | const title = "jsgrids - Spreadsheet and data grid libraries for JavaScript"; 10 | const description = 11 | "A searchable list of popular spreadsheets and data grid libraries for JavaScript and TypeScript with framework (React, Vue, Angular, Svelte, Ember, jQuery, Vanilla JS), popularity, and feature information."; 12 | const url = "https://jsgrids.statico.io"; 13 | const image = { 14 | url: url + "/jsgrids.png", 15 | width: "1200", 16 | height: "630", 17 | alt: "Screenshot of jsgrids", 18 | }; 19 | 20 | export const metadata: Metadata = { 21 | title, 22 | description, 23 | robots: "index,follow", 24 | openGraph: { 25 | siteName: name, 26 | title, 27 | url, 28 | type: "website", 29 | description, 30 | images: [ 31 | { 32 | url: image.url, 33 | alt: image.alt, 34 | width: parseInt(image.width), 35 | height: parseInt(image.height), 36 | }, 37 | ], 38 | }, 39 | twitter: { 40 | card: "summary_large_image", 41 | creator: "@statico", 42 | title, 43 | description, 44 | site: name, 45 | images: [image.url], 46 | }, 47 | other: { 48 | "twitter:url": url, 49 | }, 50 | }; 51 | 52 | export default function RootLayout({ 53 | children, 54 | }: { 55 | children: React.ReactNode; 56 | }) { 57 | return ( 58 | 59 | 60 | 66 | {children} 67 | 68 | 69 | {process.env.NODE_ENV === "production" && ( 70 | // https://github.com/statico/femtostats 71 |