Table

Professional data tables for property listings, client management, and analytics with sorting and filtering.

Table Variants

Standard Table

Property ID Address Type Price Status Actions
#LYD001 Kurfürstendamm 123, Berlin Apartment €850,000 Available
#LYD002 Prenzlauer Berg 45, Berlin House €1,250,000 Pending
#LYD003 Charlottenburg 78, Berlin Villa €2,500,000 Sold

Striped Table

Client Email Phone Interest
Max Mustermann max@example.com +49 30 12345678 Apartment, 2-3 Rooms
Anna Schmidt anna@example.com +49 30 87654321 House, Garden
John Doe john@example.com +49 30 11223344 Penthouse, City View

Sortable Table

Date Property Views Inquiries
2024-01-15 Kurfürstendamm 123 245 12
2024-01-14 Prenzlauer Berg 45 189 8
2024-01-13 Charlottenburg 78 312 15

Implementation Guide

HTML Structure

<!-- Standard Table -->
<div class="lyd-table-container">
    <table class="lyd-table">
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
                <th>Column 3</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Data 1</td>
                <td>Data 2</td>
                <td>Data 3</td>
            </tr>
        </tbody>
    </table>
</div>

<!-- Table with Status Badge -->
<td>
    <span class="table-badge success">Active</span>
</td>

<!-- Table with Actions -->
<td>
    <div class="table-actions">
        <button class="table-action">
            <svg>...</svg>
        </button>
    </div>
</td>

JavaScript for Sorting

function sortTable(columnIndex) {
    const table = document.getElementById('sortable-table');
    const tbody = table.querySelector('tbody');
    const rows = Array.from(tbody.querySelectorAll('tr'));
    const header = table.querySelectorAll('th')[columnIndex];
    
    // Toggle sort direction
    const isAsc = header.classList.contains('asc');
    
    // Remove all sort classes
    table.querySelectorAll('th').forEach(th => {
        th.classList.remove('asc', 'desc');
    });
    
    // Sort rows
    rows.sort((a, b) => {
        const aValue = a.cells[columnIndex].textContent;
        const bValue = b.cells[columnIndex].textContent;
        
        // Check if numeric
        const aNum = parseFloat(aValue);
        const bNum = parseFloat(bValue);
        
        if (!isNaN(aNum) && !isNaN(bNum)) {
            return isAsc ? bNum - aNum : aNum - bNum;
        }
        
        // String comparison
        return isAsc ? 
            bValue.localeCompare(aValue) : 
            aValue.localeCompare(bValue);
    });
    
    // Update header class
    header.classList.add(isAsc ? 'desc' : 'asc');
    
    // Reorder rows
    rows.forEach(row => tbody.appendChild(row));
}

React/Next.js Component

// components/Table.tsx
import { useState } from 'react';

interface Column {
  key: string;
  label: string;
  sortable?: boolean;
}

interface TableProps {
  columns: Column[];
  data: any[];
  striped?: boolean;
  compact?: boolean;
}

export const Table = ({ columns, data, striped = false, compact = false }: TableProps) => {
  const [sortConfig, setSortConfig] = useState<{
    key: string;
    direction: 'asc' | 'desc';
  } | null>(null);
  
  const handleSort = (key: string) => {
    let direction: 'asc' | 'desc' = 'asc';
    
    if (sortConfig?.key === key && sortConfig.direction === 'asc') {
      direction = 'desc';
    }
    
    setSortConfig({ key, direction });
  };
  
  const sortedData = sortConfig
    ? [...data].sort((a, b) => {
        const aValue = a[sortConfig.key];
        const bValue = b[sortConfig.key];
        
        if (aValue < bValue) {
          return sortConfig.direction === 'asc' ? -1 : 1;
        }
        if (aValue > bValue) {
          return sortConfig.direction === 'asc' ? 1 : -1;
        }
        return 0;
      })
    : data;
  
  return (
    <div className="lyd-table-container">
      <table className={`lyd-table ${striped ? 'striped' : ''} ${compact ? 'compact' : ''}`}>
        <thead>
          <tr>
            {columns.map((column) => (
              <th
                key={column.key}
                className={column.sortable ? 'sortable' : ''}
                onClick={() => column.sortable && handleSort(column.key)}
              >
                {column.label}
                {column.sortable && (
                  <svg className="sort-icon" viewBox="0 0 24 24">
                    <path d="M7 11l5-5m0 0l5 5m-5-5v12" />
                  </svg>
                )}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {sortedData.map((row, index) => (
            <tr key={index}>
              {columns.map((column) => (
                <td key={column.key}>{row[column.key]}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

API Reference

Class Description
.lyd-table-container Container for responsive tables
.lyd-table Base table class
.striped Alternating row colors
.compact Reduced padding variant
.bordered Full border variant
.sortable Sortable column header
.table-badge Status badge in table cells
.table-actions Action buttons container
.table-action Individual action button

Accessibility & Best Practices

Accessibility Features

  • Use semantic table elements
  • Include table captions for context
  • Provide scope attributes for headers
  • Ensure keyboard navigation
  • Add ARIA labels for actions

Best Practices

  • Keep tables simple and scannable
  • Use consistent alignment
  • Provide sorting and filtering
  • Make tables responsive
  • Use appropriate column widths
  • Include hover states for rows