Data tables,
reimagined for web.

A declarative, framework-agnostic web component. Drop it in, configure with attributes, and get a premium table experience instantly.

Start Building
Pagination
Rows:
Search
Theme:
Radius:
Numeric Paging

Data Source (JSON)

Widget Integration

Why TableOne?

Framework Agnostic

Built with standard Web Components. Use it in React, Vue, Angular, Svelte, or vanilla HTML.

Instant Setup

Just one script tag. Configure via attributes. No build step required for usage.

Premium Design

Glassmorphism headers, smooth animations, and pixel-perfect spacing out of the box.

Developer Friendly

Typed props, intuitive API, and comprehensive event system for backend integrations.

Mobile First

Automatically transforms into a card layout on mobile devices without any extra code.

Accessible

WCAG 2.1 AA compliant. Keyboard navigation, ARIA labels, and focus management included.

Use it in your ecosystem

const BASE_URL = 'https://table-one-two.vercel.app/api/render-table';

const params = new URLSearchParams({
  src: '/api/users',        // Data Source
  theme: 'dark',            // Options: 'default', 'dark', 'blue'
  pagination: 'true',
  'page-size': '10',
  search: 'true'
});

const tableUrl = `${BASE_URL}?${params.toString()}`;
console.log(tableUrl);
$baseUrl = 'https://table-one-two.vercel.app/api/render-table';

$query = http_build_query([
    'src' => '/api/users',
    'theme' => 'dark',
    'pagination' => 'true',
    'search' => 'true'
]);

$tableUrl = $baseUrl . '?' . $query;
echo $tableUrl;
import urllib.parse

base_url = "https://table-one-two.vercel.app/api/render-table"
params = {
    "src": "/api/users",
    "theme": "dark",
    "pagination": "true"
}

query = urllib.parse.urlencode(params)
table_url = f"{base_url}?{query}"
print(table_url)
require 'uri'

base_url = "https://table-one-two.vercel.app/api/render-table"
params = {
  src: "/api/users",
  theme: "dark",
  pagination: "true"
}

url = "#{base_url}?#{URI.encode_www_form(params)}"
puts url
// Cargo.toml: url = "2.2"
use url::Url;

fn main() {
    let mut url = Url::parse("https://table-one-two.vercel.app/api/render-table").unwrap();
    url.query_pairs_mut()
        .append_pair("src", "/api/users")
        .append_pair("theme", "dark")
        .append_pair("pagination", "true");

    println!("{}", url);
}
export default function TableWidget() {
  const url = "https://table-one-two.vercel.app/api/render-table?src=/api/users&theme=dark";

  return (
    <iframe 
      src={url}
      style={{ width: '100%', height: '600px', border: 'none', borderRadius: '12px' }}
      title="Data Table"
    />
  );
}
<script setup>
  const tableUrl = "https://table-one-two.vercel.app/api/render-table?src=/api/users&theme=dark";
</script>

<template>
  <iframe 
    :src="tableUrl"
    class="table-frame"
  ></iframe>
</template>

<style>
  .table-frame { width: 100%; height: 600px; border: none; border-radius: 12px; }
</style>
import { Component } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<iframe [src]="url" style="width:100%; height:600px; border:0;"></iframe>`
})
export class AppComponent {
  url: SafeResourceUrl;
  
  constructor(sanitizer: DomSanitizer) {
    this.url = sanitizer.bypassSecurityTrustResourceUrl(
      'https://table-one-two.vercel.app/api/render-table?src=/api/users&theme=dark'
    );
  }
}

Backend API Ready

Try our servers-side rendering endpoint. It generates the HTML on the fly.

Test Live Endpoint