@jalzae/vue-table
v1.0.1
Published
A flexible, native CSS Vue 3 table component with advanced features like filtering, sorting, and pagination
Maintainers
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-tableFor Nuxt 3
npm install @jalzae/vue-tableThen 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-table2. 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-table2. 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:
- QUICKSTART.md - 5-minute quick start guide
- USAGE.md - Comprehensive usage guide with examples
- API.md - Complete API reference
- RESOURCES.md - Learning paths and troubleshooting
📖 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
- Text Filter - Simple text search
- Number Filter - Numeric comparison (equals, gt, lt, gte, lte)
- Date Filter - Date range selection
- Select Filter - Multi-select with search
- Toggle Filter - Boolean status (Enabled/Disabled/Any)
- Amount Filter 💰 - Min/max amount range
- Day Filter 📅 - Select days of the week
- Like Filter ❤️ - Like/favorite status with count
- Submission Filter 📨 - Status with date range
- 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 installDevelopment Server
Start the Vite development server with interactive demo:
npm run devThis 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-tableThen add to your nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'@jalzae/vue-table/nuxt'
]
})Build
Build the library for production:
npm run buildThis generates:
dist/index.js- UMD bundledist/index.es.js- ES moduledist/styles/- CSS filesdist/types/- TypeScript declarations
Preview Build
Test the production build locally:
npm run previewType Checking
Run TypeScript type checking:
npm run type-checkLinting
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
