npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jalzae/vue-table

v1.0.1

Published

A flexible, native CSS Vue 3 table component with advanced features like filtering, sorting, and pagination

Readme

Vue Table

A flexible, native CSS Vue 3 table component with advanced features like filtering, sorting, pagination, and search. Built without Tailwind CSS for maximum compatibility and customizability.

✨ Features

  • Native CSS - No dependency on Tailwind or other CSS frameworks
  • Themeable - 40+ CSS variables for easy customization
  • Responsive - Mobile-friendly design with touch support
  • Search - Built-in debounced search functionality
  • Sort - Column sorting with visual indicators
  • Pagination - Built-in pagination controls
  • Filter - 10+ flexible filter components (Text, Number, Date, Select, Toggle, Amount, Day, Like, Submission, Comment)
  • Editable Filters - Click to edit any applied filter and reapply
  • Zero Dependencies - Only requires Vue 3
  • TypeScript - Full TypeScript support with complete types
  • Dark Mode - Built-in dark theme support
  • Advanced Filters - Pre-built filters for common and advanced use cases
  • Nuxt 3 Support - Full Nuxt 3 module support with auto-imports
  • Framework Agnostic - Works with Vue 3, Nuxt 3, and other Vue-based frameworks

📦 Installation

From npm

npm install @jalzae/vue-table

For Nuxt 3

npm install @jalzae/vue-table

Then add to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: [
    '@jalzae/vue-table/nuxt'
  ]
})

The component will be auto-imported in your Nuxt app.

From GitHub (Local Development)

# Clone the repository
git clone https://github.com/yourusername/jalz-table.git
cd jalz-table

# Install dependencies
npm install

# Start development server
npm run dev

# Build the library
npm run build

# Test the build
npm run preview

🚀 Quick Start

Vue 3 Project

1. Basic Setup

Install the package in your Vue 3 project:

npm install @jalzae/vue-table

2. Import CSS

In your main.ts or App.vue:

// Import component styles (required)
import '@jalzae/vue-table/dist/styles/variables.css'
import '@jalzae/vue-table/dist/styles/base.css'

3. Use the Table Component

<template>
  <Table
    :columns="columns"
    :rows="rows"
    title="Users"
    show-header
    show-search
    show-pagination
    :total="100"
    :current-page="1"
    :per-page="10"
  />
</template>

<script setup lang="ts">
import { Table } from '@jalzae/vue-table'
import '@jalzae/vue-table/dist/styles/variables.css'
import '@jalzae/vue-table/dist/styles/base.css'

const columns = [
  { key: 'id', label: 'ID', sortable: true },
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email' },
]

const rows = [
  { id: 1, name: 'John Doe', email: '[email protected]' },
  { id: 2, name: 'Jane Smith', email: '[email protected]' },
]
</script>

Nuxt 3 Project

1. Install Package

npm install @jalzae/vue-table

2. Configure Module

Add the module to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: [
    '@jalzae/vue-table/nuxt'
  ]
})

3. Use in Your Pages

The Table component and CSS will be auto-imported. Just use it directly:

<template>
  <div>
    <Table
      :columns="columns"
      :rows="rows"
      title="Users"
      show-header
      show-search
      show-pagination
      enable-auto-fetch
      :total="total"
      :current-page="currentPage"
      :per-page="perPage"
      @filter="handleFilters"
      @search="handleSearch"
      @page-change="handlePageChange"
      @per-page-change="handlePerPageChange"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const columns = [
  { key: 'id', label: 'ID', sortable: true },
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email' },
]

const rows = ref([])
const total = ref(0)
const currentPage = ref(1)
const perPage = ref(10)

const fetchData = async (page = 1) => {
  const response = await fetch(`/api/users?page=${page}&perPage=${perPage.value}`)
  const data = await response.json()
  rows.value = data.rows
  total.value = data.total
}

const handleSearch = (query: string) => {
  currentPage.value = 1
  // Implement search logic
}

const handleFilters = (filters: any[]) => {
  currentPage.value = 1
  // Implement filter logic
}

const handlePageChange = (page: number) => {
  currentPage.value = page
  fetchData(page)
}

const handlePerPageChange = (per: number) => {
  perPage.value = per
  currentPage.value = 1
  fetchData(1)
}

onMounted(() => {
  fetchData()
})
</script>

📚 Documentation

For detailed documentation, see:

📖 Examples

Basic Usage

<template>
  <Table
    :columns="columns"
    :rows="rows"
    title="Users"
    show-header
    show-search
    show-pagination
    :show-pagination="true"
    :total="100"
    :current-page="1"
    :per-page="10"
  />
</template>

<script setup lang="ts">
import { Table } from '@jalzae/vue-table';

const columns = [
  { key: 'id', label: 'ID', sortable: true },
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email' },
  { key: 'role', label: 'Role' },
];

const rows = [
  { id: 1, name: 'John Doe', email: '[email protected]', role: 'Admin' },
  { id: 2, name: 'Jane Smith', email: '[email protected]', role: 'User' },
  // ... more rows
];
</script>

<style>
/* Import the CSS variables for theming */
@import '@jalzae/vue-table/dist/styles/variables.css';
@import '@jalzae/vue-table/dist/styles/base.css';
</style>

Props

Table Component

| Prop | Type | Default | Description | |------|------|---------|-------------| | columns | TableColumn[] | [] | Column definitions | | rows | TableRow[] | [] | Table data rows | | title | string | '' | Table title | | showHeader | boolean | true | Show table header | | showSearch | boolean | false | Show search bar | | searchPlaceholder | string | 'Search...' | Search input placeholder | | showFilter | boolean | false | Show filter controls | | loading | boolean | false | Show loading state | | showPagination | boolean | false | Show pagination | | total | number | 0 | Total number of records | | currentPage | number | 1 | Current page number | | perPage | number | 10 | Records per page | | actions | TableAction[] | [] | Row action buttons | | actionButtons | TableAction[] | [] | Header action buttons | | sortBy | string | '' | Current sort field | | sortOrder | 'asc' \| 'desc' | 'asc' | Sort order | | customClass | string | '' | Custom CSS class | | striped | boolean | false | Striped rows | | hoverable | boolean | true | Hover effect on rows | | compact | boolean | false | Compact spacing | | enableAutoFetch | boolean | false | Auto-fetch when filters change |

Column Definition

interface TableColumn {
  key: string;          // Data key
  label: string;        // Display label
  sortable?: boolean;   // Sortable column
  class?: string;       // Custom column CSS class
  type?: string;        // Column type ('text', 'date', 'boolean', etc.)
}

Row Action Definition

interface TableAction {
  id: string;           // Unique action ID
  label: string;        // Display label
  event: string;        // Event name to emit
  icon?: string;        // Icon name
  variant?: string;     // Button variant
}

Filter Components

Available Filters

  1. Text Filter - Simple text search
  2. Number Filter - Numeric comparison (equals, gt, lt, gte, lte)
  3. Date Filter - Date range selection
  4. Select Filter - Multi-select with search
  5. Toggle Filter - Boolean status (Enabled/Disabled/Any)
  6. Amount Filter 💰 - Min/max amount range
  7. Day Filter 📅 - Select days of the week
  8. Like Filter ❤️ - Like/favorite status with count
  9. Submission Filter 📨 - Status with date range
  10. Comment Filter 💬 - Comment count with operators and text search

Using Filters

All filters are clickable and editable:

  • Click any applied filter to edit its values
  • Modify and reapply without losing context
  • Toggle filters on/off with the enable/disable button
  • Remove filters with the X button

Events

| Event | Payload | Description | |-------|---------|-------------| | search | string | Fired when search query changes | | filter | Filter[] | Fired when filters change | | sort | { field: string, order: 'asc' \| 'desc' } | Fired when sorting changes | | page-change | number | Fired when page changes | | per-page-change | number | Fired when items per page changes | | row-click | TableRow | Fired when row action is clicked |

Theming

CSS Variables

All colors and spacing use CSS custom properties that can be overridden:

:root {
  /* Colors */
  --color-primary: #AD5160;
  --color-primary-light: #faeef0;
  --color-primary-dark: #8d4150;

  --color-bg: #ffffff;
  --color-bg-secondary: #f9fafb;
  --color-bg-tertiary: #f3f4f6;

  --color-border: #e5e7eb;
  --color-text: #1f2937;
  --color-text-secondary: #6b7280;

  /* Spacing */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;

  /* Border Radius */
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;

  /* Other... */
}

Dark Mode

[data-theme="dark"] {
  --color-bg: #1f2937;
  --color-bg-secondary: #111827;
  --color-text: #f3f4f6;
  /* ... */
}

Examples

With Actions

<template>
  <Table
    :columns="columns"
    :rows="rows"
    :actions="[
      { id: 'edit', label: 'Edit', event: 'edit-row', icon: 'pencil' },
      { id: 'delete', label: 'Delete', event: 'delete-row', icon: 'trash' }
    ]"
    @edit-row="handleEdit"
    @delete-row="handleDelete"
  />
</template>

<script setup>
const handleEdit = (row) => {
  console.log('Edit:', row);
};

const handleDelete = (row) => {
  console.log('Delete:', row);
};
</script>

With Search and Sort

<template>
  <Table
    :columns="columns"
    :rows="rows"
    show-search
    :sort-by="sortBy"
    :sort-order="sortOrder"
    @search="handleSearch"
    @sort="handleSort"
  />
</template>

<script setup>
import { ref } from 'vue';

const sortBy = ref('');
const sortOrder = ref('asc');

const handleSearch = (query) => {
  // Filter rows based on query
};

const handleSort = ({ field, order }) => {
  sortBy.value = field;
  sortOrder.value = order;
  // Sort rows
};
</script>

Complete Example with API

<template>
  <Table
    :columns="columns"
    :rows="tableData"
    :loading="loading"
    :total="total"
    :current-page="currentPage"
    :per-page="perPage"
    title="Users"
    show-search
    show-filter
    show-pagination
    enable-auto-fetch
    :actions="actions"
    @search="search"
    @filter="applyFilters"
    @page-change="changePage"
    @per-page-change="changePerPage"
    @edit-row="editRow"
    @delete-row="deleteRow"
  />
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Table } from '@jalzae/vue-table';

const columns = [
  { key: 'id', label: 'ID', sortable: true },
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email' },
];

const tableData = ref([]);
const loading = ref(false);
const total = ref(0);
const currentPage = ref(1);
const perPage = ref(10);

const actions = [
  { id: 'edit', label: 'Edit', event: 'edit-row', icon: 'pencil' },
  { id: 'delete', label: 'Delete', event: 'delete-row', icon: 'trash' },
];

const fetchData = async (page = 1, query = '', filters = []) => {
  loading.value = true;
  try {
    const response = await fetch(
      `/api/users?page=${page}&perPage=${perPage.value}&search=${query}&filters=${JSON.stringify(filters)}`
    );
    const data = await response.json();
    tableData.value = data.rows;
    total.value = data.total;
  } finally {
    loading.value = false;
  }
};

const search = (query) => {
  currentPage.value = 1;
  fetchData(1, query);
};

const applyFilters = (filters) => {
  currentPage.value = 1;
  fetchData(1, '', filters);
};

const changePage = (page) => {
  currentPage.value = page;
  fetchData(page);
};

const changePerPage = (per) => {
  perPage.value = per;
  currentPage.value = 1;
  fetchData(1);
};

const editRow = (row) => {
  // Handle edit
  console.log('Edit:', row);
};

const deleteRow = (row) => {
  // Handle delete
  console.log('Delete:', row);
};

onMounted(() => {
  fetchData();
});
</script>

Components

Base Components

All base components are available for use:

import {
  Table,
  Button,
  Icon,
  Empty,
  Pagination,
  Toggle,
} from '@jalzae/vue-table';

Icon Component

<Icon icon="search" size="16" color="currentColor" />

Available icons: search, filter, chevrondown, chevronup, x, plus, trash, pencil, eye, download, upload, save, elipsisvertical, and more.

Button Component

<Button variant="primary" size="md" @click="handleClick">
  Click Me
</Button>

Variants: primary, secondary, danger, success, warning, info, ghost, cancel

Sizes: sm, md, lg

Utilities

Helper functions are available:

import {
  formatNumber,
  formatDecimal,
  formatDate,
  debounce,
  throttle,
  isEmpty,
  // ... more utilities
} from '@jalzae/vue-table';

🔧 Development

Setup

Clone the repository and install dependencies:

git clone https://github.com/yourusername/jalz-table.git
cd jalz-table
npm install

Development Server

Start the Vite development server with interactive demo:

npm run dev

This starts a local server at http://localhost:5173 with a complete interactive demo showing:

  • Basic table functionality
  • All components (Button, Icon, Toggle, Pagination, etc.)
  • All filter components with edit capabilities
  • Theming and dark mode
  • Complete documentation

Nuxt 3 Integration

To test with Nuxt 3, create a Nuxt project and link this package:

# In your Nuxt project
npm install ../path-to-jalz-table

# Or using npm link
cd ../jalz-table
npm link
cd ../your-nuxt-project
npm link @jalzae/vue-table

Then add to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: [
    '@jalzae/vue-table/nuxt'
  ]
})

Build

Build the library for production:

npm run build

This generates:

  • dist/index.js - UMD bundle
  • dist/index.es.js - ES module
  • dist/styles/ - CSS files
  • dist/types/ - TypeScript declarations

Preview Build

Test the production build locally:

npm run preview

Type Checking

Run TypeScript type checking:

npm run type-check

Linting

Check and fix code style:

npm run lint

📁 Project Structure

jalz-table/
├── src/
│   ├── components/
│   │   ├── Table.vue              # Main table component
│   │   ├── base/                  # Base components
│   │   │   ├── Button.vue
│   │   │   ├── Icon.vue
│   │   │   ├── Empty.vue
│   │   │   ├── Pagination.vue
│   │   │   └── Toggle.vue
│   │   └── Filter/                # Filter components
│   │       ├── Text.vue
│   │       ├── Number.vue
│   │       ├── DateFilter.vue
│   │       ├── Select.vue
│   │       ├── Toggle.vue
│   │       ├── Amount.vue
│   │       ├── Day.vue
│   │       ├── Like.vue
│   │       ├── Submission.vue
│   │       └── Comment.vue
│   ├── styles/
│   │   ├── variables.css          # CSS custom properties
│   │   └── base.css               # Global styles
│   ├── types/
│   │   └── index.ts               # TypeScript types
│   ├── utils/
│   │   └── helpers.ts             # Utility functions
│   ├── App.vue                    # Demo app
│   ├── main.ts                    # Entry point for dev
│   └── index.ts                   # Library exports
├── index.html                     # Dev server entry
├── vite.config.ts
├── tsconfig.json
├── package.json
└── README.md

🎨 Customization

CSS Variables

Override default CSS variables in your global CSS:

:root {
  --color-primary: #your-color;
  --spacing-md: 1.2rem;
  --radius-lg: 1rem;
  /* ... more variables */
}

See src/styles/variables.css for all available variables.

Dark Mode

Enable dark mode by setting the data-theme attribute:

document.documentElement.setAttribute('data-theme', 'dark')

Or with conditional rendering:

<div :data-theme="isDarkMode ? 'dark' : null">
  <!-- Your app here -->
</div>

📝 License

MIT - See LICENSE for details

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

💬 Support

For issues and questions, please visit GitHub Issues