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

rijal-footable

v0.0.3

Published

making tables not war

Readme

FooTable Components

This is a Vue 3 conversion of the React table components with enhanced accessibility, centralized styling system, and full support for colspan and rowspan attributes.

🚀 Key Features

  • Accessibility First: Full ARIA support, keyboard navigation, screen reader friendly
  • Centralized Styling: Configurable theme system with TypeScript support
  • Colspan/Rowspan: Full support for complex table layouts
  • Vue 3 + TypeScript: Modern composition API with type safety
  • Responsive Design: Mobile-friendly with Tailwind CSS

Components

Basic Components

  • FooTable.vue - Main table wrapper with accessibility features
  • TableHead.vue - Semantic table header with proper roles
  • TableBody.vue - Table body wrapper
  • TableRow.vue - Table row with variant support
  • TableColumn.vue - Table cell (th/td) with colspan/rowspan and accessibility
  • TableSorter.vue - Sort indicator with ARIA labels
  • TableDataRow.vue - Special row for loading/empty states

Advanced Components

  • CompactTable.vue - Complete table with sorting and pagination
  • TablePagination.vue - Accessible pagination component
  • useTable.ts - Composition API hook for table state management

Styling System

  • tableStyles.ts - Centralized styling configuration
  • useTableStyles.ts - Composable for reactive styling

🎨 Styling System

Quick Start with Default Styling

<template>
	<FooTable>
		<TableHead>
			<TableRow>
				<TableColumn variant="head">Name</TableColumn>
				<TableColumn variant="head">Email</TableColumn>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow v-for="user in users" :key="user.id" variant="hover">
				<TableColumn>{{ user.name }}</TableColumn>
				<TableColumn>{{ user.email }}</TableColumn>
			</TableRow>
		</TableBody>
	</FooTable>
</template>

<script setup>
import {
	FooTable,
	TableHead,
	TableBody,
	TableRow,
	TableColumn,
} from "./FooTable"
</script>

Custom Styling Configuration

<template>
	<div>
		<!-- Your tables will use the custom theme -->
		<FooTable>
			<!-- table content -->
		</FooTable>
	</div>
</template>

<script setup>
import { provideTableStyles } from "./VueTable/useTableStyles"
import { modernTableStyles } from "./VueTable/tableStyles"

// Provide custom styling for all child table components
provideTableStyles(modernTableStyles)
</script>

Available Themes

import {
	defaultTableStyles, // Standard gray theme
	modernTableStyles, // Slate-based modern theme
	compactTableStyles, // Compact spacing theme
} from "./VueTable/tableStyles"

Creating Custom Themes

import { createTableStyles } from "./VueTable/tableStyles"

const myCustomTheme = createTableStyles({
	table: {
		base: "w-full text-sm border-2 border-blue-500",
	},
	head: {
		base: "bg-blue-100 text-blue-900 font-bold",
	},
	row: {
		hover: "hover:bg-blue-50 transition-colors",
	},
})

🔧 SonarQube Compliance

Problem Resolved

The SonarQube warning "Add <th> headers to this <Footable>" (Web:S5256) is now resolved.

What We Fixed

  • ✅ All tables have proper <thead> sections with <th> elements
  • ✅ Header cells use role="columnheader" and scope="col"
  • ✅ Tables have role="table" and descriptive aria-label
  • ✅ Sortable headers include aria-sort and tabindex attributes
  • ✅ All table sections have appropriate ARIA roles

Before (SonarQube Warning)

<Footable>
	<tbody>
		<tr>
			<td>Name</td>
			<!-- ❌ Should be <th> -->
			<td>Email</td>
		</tr>
	</tbody>
</Footable>

After (SonarQube Compliant)

<table role="table" aria-label="Data table">
  <thead role="rowgroup">
    <tr role="row">
      <th role="columnheader" scope="col">Name</th>
      <!-- ✅ Proper header -->
      <th role="columnheader" scope="col">Email</th>
    </tr>
  </thead>
  <tbody role="rowgroup">
    <!-- data rows -->
  </tbody>
</Footable>

📋 Usage Examples

Basic Table with Accessibility

<template>
  <Table aria-label="Employee information">
    <TableHead>
      <TableRow>
        <TableColumn variant="head" id="name">Name</TableColumn>
        <TableColumn variant="head" id="email">Email</TableColumn>
        <TableColumn variant="head" id="dept">Department</TableColumn>
      </TableRow>
    </TableHead>
    <TableBody>
      <TableRow v-for="emp in employees" :key="emp.id" variant="hover">
        <TableColumn>{{ emp.name }}</TableColumn>
        <TableColumn>{{ emp.email }}</TableColumn>
        <TableColumn>{{ emp.department }}</TableColumn>
      </TableRow>
    </TableBody>
  </FooTable>
</template>

Table with Colspan

<template>
	<FooTable>
		<TableHead>
			<TableRow>
				<TableColumn variant="head">Name</TableColumn>
				<TableColumn variant="head" :col-span="2"
					>Contact Information</TableColumn
				>
			</TableRow>
			<TableRow>
				<TableColumn variant="head">Full Name</TableColumn>
				<TableColumn variant="head">Email</TableColumn>
				<TableColumn variant="head">Phone</TableColumn>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow variant="hover">
				<TableColumn>John Doe</TableColumn>
				<TableColumn>[email protected]</TableColumn>
				<TableColumn>555-0123</TableColumn>
			</TableRow>
		</TableBody>
	</FooTable>
</template>

Table with Rowspan

<template>
	<FooTable>
		<TableHead>
			<TableRow>
				<TableColumn variant="head">Department</TableColumn>
				<TableColumn variant="head">Employee</TableColumn>
				<TableColumn variant="head">Position</TableColumn>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow variant="hover">
				<TableColumn :row-span="3">Engineering</TableColumn>
				<TableColumn>John Doe</TableColumn>
				<TableColumn>Senior Developer</TableColumn>
			</TableRow>
			<TableRow variant="hover">
				<TableColumn>Jane Smith</TableColumn>
				<TableColumn>Frontend Developer</TableColumn>
			</TableRow>
			<TableRow variant="hover">
				<TableColumn>Bob Johnson</TableColumn>
				<TableColumn>DevOps Engineer</TableColumn>
			</TableRow>
		</TableBody>
	</FooTable>
</template>

Sortable CompactTable

<template>
	<CompactTable
		:columns="columns"
		:data="data"
		:pagination="paginationOptions"
		:loading="loading"
		aria-label="User management table"
	/>
</template>

<script setup>
import { CompactTable } from "./VueTable"

const columns = [
	{ id: "name", label: "Name", sortable: true, ordering: 1 },
	{ id: "email", label: "Email", sortable: true, ordering: 2, align: "left" },
	{
		id: "role",
		label: "Role",
		sortable: false,
		ordering: 3,
		align: "center",
	},
]

const data = [
	{ name: "John Doe", email: "[email protected]", role: "Admin" },
	{ name: "Jane Smith", email: "[email protected]", role: "User" },
]
</script>

🎛️ Component Props

TableColumn Props

  • variant?: "head" | "body" | "footer" - Determines if it renders as th or td
  • id?: string - Unique identifier for the column
  • align?: "left" | "right" | "center" - Text alignment
  • className?: string - Additional CSS classes
  • colSpan?: number - Number of columns to span horizontally
  • rowSpan?: number - Number of rows to span vertically
  • sort?: (id: string) => void - Sort function for clickable headers
  • sortDirection?: 'asc' | 'desc' | null - Current sort direction for ARIA

TableRow Props

  • className?: string - Additional CSS classes
  • variant?: 'base' | 'hover' | 'striped' - Row styling variant

Table Props

  • ariaLabel?: string - Accessible label for the table
  • ariaDescribedBy?: string - ID of element describing the table

CompactTable Column Interface

interface ColumnInterface {
	label: string
	id: string
	sortable?: boolean
	ordering?: number
	colSpan?: number
	rowSpan?: number
	align?: AlignmentType
}

🚀 Installation

  1. Copy the VueTable directory to your Vue project
  2. Import the components you need
  3. Ensure Tailwind CSS is configured in your project
  4. Optionally configure custom styling themes

📦 What's Included

VueTable/
├── Table.vue                 # Main table component
├── TableHead.vue            # Table header
├── TableBody.vue            # Table body
├── TableRow.vue             # Table row
├── TableColumn.vue          # Table cell with accessibility
├── TableSorter.vue          # Sort indicator
├── TableDataRow.vue         # Loading/empty states
├── TablePagination.vue      # Pagination component
├── CompactTable.vue         # Complete table solution
├── useTable.ts              # Table state management
├── tableStyles.ts           # Styling configuration
├── useTableStyles.ts        # Styling composable
├── index.ts                 # Export file
├── README.md                # This file
├── TableExample.vue         # Usage examples
└── StyleTest.vue            # Styling system test

🔄 Migration from Previous Version

If you're upgrading from the previous version:

  1. Styling: Replace hardcoded classes with the new styling system
  2. Accessibility: Add aria-label props to your tables
  3. Headers: Ensure you're using TableColumn with variant="head" in TableHead
  4. Sorting: Pass sortDirection prop for proper ARIA attributes

🌟 Key Improvements

  1. SonarQube Compliance: No more Web:S5256 warnings
  2. Better Accessibility: Screen reader friendly with proper ARIA
  3. Centralized Styling: Easy theming and customization
  4. Type Safety: Full TypeScript support
  5. Performance: Optimized with Vue 3 Composition API
  6. Maintainability: Clean, modular architecture

🤝 Contributing

The components follow Vue 3 best practices and accessibility guidelines. When contributing:

  • Maintain ARIA compliance
  • Use the centralized styling system
  • Include TypeScript types
  • Test with screen readers
  • Ensure SonarQube compliance