Table avec Datatable - Bootstrap 5

🏷️ Extraits & Composants HTML 📅 27/03/2026 17:00:00 👤 Mezgani Said
Bootstrap 5 Datatable Table Template Filter Table Dashboard

Table avec Datatable optimisée pour la visualisation et l'interaction. Design moderne et responsive.

<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8" />
  <meta name="copyright" content="MEZGANI Said" />
  <meta name="author" content="AngularForAll" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Snippet Datatable Bootstrap 5 2026 230400337 | AngularForAll</title>
<!-- Bootstrap 5 -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
  
  <!-- DataTables Bootstrap 5 -->
  <link href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/buttons/2.4.2/css/buttons.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/select/1.7.0/css/select.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/searchpanes/2.2.0/css/searchPanes.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/searchbuilder/1.6.0/css/searchBuilder.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/datetime/1.5.1/css/dataTables.dateTime.min.css" rel="stylesheet">
  
  <!-- Font Awesome pour les icônes -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
  
  <style>
    body {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      padding: 2rem 0;
      font-family: 'Inter', system-ui, sans-serif;
    }
    
    .container-custom {
      background: white;
      border-radius: 20px;
      padding: 2rem;
      box-shadow: 0 20px 60px rgba(0,0,0,0.2);
    }
    
    h1 {
      background: linear-gradient(135deg, #667eea, #764ba2);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      font-weight: 700;
    }
    
    .table-container {
      overflow-x: auto;
    }
    
    /* Styles personnalisés pour DataTables */
    .dt-buttons {
      margin-bottom: 1rem;
    }
    
    .dt-button {
      background: linear-gradient(135deg, #667eea, #764ba2) !important;
      color: white !important;
      border: none !important;
      border-radius: 8px !important;
      padding: 8px 16px !important;
      margin-right: 8px !important;
      font-weight: 500 !important;
      transition: all 0.3s !important;
    }
    
    .dt-button:hover {
      transform: translateY(-2px) !important;
      box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4) !important;
    }
    
    .dataTables_filter input {
      border-radius: 8px !important;
      border: 2px solid #e0e0e0 !important;
      padding: 8px 16px !important;
      margin-left: 8px !important;
    }
    
    .dataTables_filter input:focus {
      border-color: #667eea !important;
      outline: none !important;
      box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
    }
    
    .dataTables_length select {
      border-radius: 8px !important;
      border: 2px solid #e0e0e0 !important;
      padding: 6px 12px !important;
    }
    
    .page-item.active .page-link {
      background: linear-gradient(135deg, #667eea, #764ba2) !important;
      border-color: #667eea !important;
    }
    
    .page-link {
      color: #667eea !important;
      border-radius: 8px !important;
      margin: 0 4px !important;
    }
    
    .page-link:hover {
      background: #f3f4f6 !important;
    }
    
    table.dataTable thead th {
      background: #f8f9fa;
      font-weight: 600;
      border-bottom: 2px solid #dee2e6;
    }
    
    .badge-status {
      padding: 6px 12px;
      border-radius: 20px;
      font-weight: 500;
      font-size: 12px;
    }
    
    .status-active {
      background: #d1fae5;
      color: #065f46;
    }
    
    .status-inactive {
      background: #fee2e2;
      color: #991b1b;
    }
    
    .status-pending {
      background: #fef3c7;
      color: #92400e;
    }
    
    .stats-card {
      background: linear-gradient(135deg, #667eea, #764ba2);
      color: white;
      border-radius: 16px;
      padding: 1.5rem;
      margin-bottom: 2rem;
    }
    
    .stats-number {
      font-size: 2.5rem;
      font-weight: 700;
    }
    
    .btn-action {
      padding: 4px 10px;
      border-radius: 6px;
      margin: 0 4px;
      transition: all 0.2s;
    }
    
    .btn-action:hover {
      transform: scale(1.1);
    }
  </style>
</head>
<body>

<div class="container">
  
  <!-- Header -->
  <div class="text-center mb-4">
    <h1 class="display-4 mb-3">
      <i class="fas fa-table me-3" style="background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent;"></i>
      DataTable Bootstrap 5
    </h1>
    <p class="lead text-white-50">Gestion avancée avec recherche, filtres, pagination, tri et export</p>
  </div>
  
  <!-- Container principal -->
  <div class="container-custom">
    
    <!-- Statistiques -->
    <div class="row mb-4">
      <div class="col-md-4 mb-3">
        <div class="stats-card">
          <i class="fas fa-users fa-2x mb-2"></i>
          <div class="stats-number" id="totalRecords">0</div>
          <div>Total enregistrements</div>
        </div>
      </div>
      <div class="col-md-4 mb-3">
        <div class="stats-card" style="background: linear-gradient(135deg, #f59e0b, #ef4444);">
          <i class="fas fa-filter fa-2x mb-2"></i>
          <div class="stats-number" id="filteredRecords">0</div>
          <div>Enregistrements filtrés</div>
        </div>
      </div>
      <div class="col-md-4 mb-3">
        <div class="stats-card" style="background: linear-gradient(135deg, #10b981, #059669);">
          <i class="fas fa-database fa-2x mb-2"></i>
          <div class="stats-number" id="activeFilters">0</div>
          <div>Filtres actifs</div>
        </div>
      </div>
    </div>
    
    <!-- Filtres rapides -->
    <div class="row mb-4">
      <div class="col-12">
        <div class="d-flex flex-wrap gap-2">
          <button class="btn btn-outline-primary filter-quick" data-status="all">
            <i class="fas fa-list me-2"></i>Tous
          </button>
          <button class="btn btn-outline-success filter-quick" data-status="Actif">
            <i class="fas fa-check-circle me-2"></i>Actifs
          </button>
          <button class="btn btn-outline-warning filter-quick" data-status="En attente">
            <i class="fas fa-clock me-2"></i>En attente
          </button>
          <button class="btn btn-outline-danger filter-quick" data-status="Inactif">
            <i class="fas fa-times-circle me-2"></i>Inactifs
          </button>
        </div>
      </div>
    </div>
    
    <!-- Table -->
    <div class="table-container">
      <table id="mainTable" class="table table-striped table-hover" style="width:100%">
        <thead>
          <tr>
            <th>ID</th>
            <th>Nom complet</th>
            <th>Email</th>
            <th>Téléphone</th>
            <th>Département</th>
            <th>Poste</th>
            <th>Date d'embauche</th>
            <th>Salaire (€)</th>
            <th>Statut</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody id="tableBody">
          <!-- Les données seront injectées ici -->
        </tbody>
        <tfoot>
          <tr>
            <th>ID</th>
            <th>Nom complet</th>
            <th>Email</th>
            <th>Téléphone</th>
            <th>Département</th>
            <th>Poste</th>
            <th>Date d'embauche</th>
            <th>Salaire (€)</th>
            <th>Statut</th>
            <th>Actions</th>
          </tr>
        </tfoot>
      </table>
    </div>
    
    <!-- Légende -->
    <div class="mt-4 p-3 bg-light rounded-3">
      <h6 class="mb-3"><i class="fas fa-info-circle me-2"></i>Fonctionnalités disponibles :</h6>
      <div class="row">
        <div class="col-md-3">
          <i class="fas fa-search text-primary me-2"></i>Recherche globale
        </div>
        <div class="col-md-3">
          <i class="fas fa-filter text-success me-2"></i>Filtres par colonne
        </div>
        <div class="col-md-3">
          <i class="fas fa-sort text-warning me-2"></i>Tri multi-colonnes
        </div>
        <div class="col-md-3">
          <i class="fas fa-file-export text-info me-2"></i>Export (CSV, Excel, PDF)
        </div>
      </div>
    </div>
    
  </div>
</div>

<!-- Scripts -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>

<!-- DataTables -->
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap5.min.js"></script>

<!-- Extensions DataTables -->
<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.print.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.colVis.min.js"></script>

<script src="https://cdn.datatables.net/select/1.7.0/js/dataTables.select.min.js"></script>
<script src="https://cdn.datatables.net/searchpanes/2.2.0/js/dataTables.searchPanes.min.js"></script>
<script src="https://cdn.datatables.net/searchpanes/2.2.0/js/searchPanes.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/searchbuilder/1.6.0/js/dataTables.searchBuilder.min.js"></script>
<script src="https://cdn.datatables.net/searchbuilder/1.6.0/js/searchBuilder.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/datetime/1.5.1/js/dataTables.dateTime.min.js"></script>

<!-- JSZip pour export Excel -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<!-- PDFMake pour export PDF -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>

<script>
  // Données de démonstration (100 enregistrements)
  const demoData = [];
  const firstNames = ['Jean', 'Marie', 'Pierre', 'Sophie', 'Thomas', 'Julie', 'Nicolas', 'Emma', 'Lucas', 'Léa', 'Antoine', 'Camille', 'Paul', 'Sarah', 'David', 'Claire', 'Michel', 'Céline', 'François', 'Isabelle'];
  const lastNames = ['Martin', 'Bernard', 'Dubois', 'Thomas', 'Robert', 'Richard', 'Petit', 'Durand', 'Leroy', 'Moreau', 'Simon', 'Laurent', 'Lefebvre', 'Michel', 'Garcia', 'David', 'Bertrand', 'Roux', 'Vincent', 'Fournier'];
  const departments = ['Informatique', 'Marketing', 'Ressources Humaines', 'Finance', 'Commercial', 'Production', 'R&D', 'Service Client', 'Logistique', 'Direction'];
  const positions = {
    'Informatique': ['Développeur', 'Admin Système', 'Chef de projet', 'Architecte', 'DevOps'],
    'Marketing': ['Community Manager', 'SEO Manager', 'Growth Hacker', 'Brand Manager', 'Traffic Manager'],
    'Ressources Humaines': ['Recruteur', 'HRBP', 'Formateur', 'Payroll', 'Talent Acquisition'],
    'Finance': ['Comptable', 'Contrôleur', 'Auditeur', 'Trésorier', 'Analyste Financier'],
    'Commercial': ['Commercial', 'Account Manager', 'Sales Dev', 'Key Account', 'Business Dev'],
    'Production': ['Opérateur', 'Chef d\'équipe', 'Responsable Qualité', 'Technicien', 'Superviseur'],
    'R&D': ['Chercheur', 'Ingénieur R&D', 'Scientifique', 'Lab Manager', 'Innovation Manager'],
    'Service Client': ['Conseiller', 'Superviseur', 'Quality Analyst', 'Team Leader', 'Support Tech'],
    'Logistique': ['Magasinier', 'Responsable Logistique', 'Planificateur', 'Gestionnaire Stock', 'Transport Manager'],
    'Direction': ['Directeur', 'Directeur Adjoint', 'Secrétaire Général', 'Chief of Staff', 'Executive Assistant']
  };
  const statuses = ['Actif', 'Inactif', 'En attente'];

  // Génération des données
  for (let i = 1; i <= 100; i++) {
    const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
    const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
    const department = departments[Math.floor(Math.random() * departments.length)];
    const position = positions[department][Math.floor(Math.random() * positions[department].length)];
    const status = statuses[Math.floor(Math.random() * statuses.length)];
    
    // Date d'embauche aléatoire (entre 2015 et 2024)
    const hireDate = new Date(2015 + Math.floor(Math.random() * 10), Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1);
    const hireDateStr = hireDate.toLocaleDateString('fr-FR');
    
    // Salaire entre 25000 et 120000
    const salary = Math.floor(Math.random() * 95000) + 25000;
    
    demoData.push({
      id: i,
      name: `${firstName} ${lastName}`,
      email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@entreprise.com`,
      phone: `06 ${Math.floor(Math.random() * 90 + 10)} ${Math.floor(Math.random() * 90 + 10)} ${Math.floor(Math.random() * 90 + 10)} ${Math.floor(Math.random() * 90 + 10)}`,
      department: department,
      position: position,
      hireDate: hireDateStr,
      salary: salary,
      status: status
    });
  }

  // Tri par ID
  demoData.sort((a, b) => a.id - b.id);

  // Remplissage du tableau
  const tbody = document.getElementById('tableBody');
  demoData.forEach(item => {
    const row = document.createElement('tr');
    
    let statusClass = '';
    if (item.status === 'Actif') statusClass = 'status-active';
    else if (item.status === 'Inactif') statusClass = 'status-inactive';
    else statusClass = 'status-pending';
    
    row.innerHTML = `
      <td>${item.id}</td>
      <td><i class="fas fa-user me-2 text-primary"></i>${item.name}</td>
      <td><i class="fas fa-envelope me-2 text-secondary"></i>${item.email}</td>
      <td><i class="fas fa-phone me-2 text-success"></i>${item.phone}</td>
      <td><span class="badge bg-info">${item.department}</span></td>
      <td>${item.position}</td>
      <td><i class="fas fa-calendar me-2 text-warning"></i>${item.hireDate}</td>
      <td class="text-end fw-semibold">${item.salary.toLocaleString('fr-FR')} €</td>
      <td><span class="badge-status ${statusClass}">${item.status}</span></td>
      <td>
        <button class="btn btn-sm btn-outline-primary btn-action" onclick="viewItem(${item.id})" title="Voir">
          <i class="fas fa-eye"></i>
        </button>
        <button class="btn btn-sm btn-outline-warning btn-action" onclick="editItem(${item.id})" title="Modifier">
          <i class="fas fa-edit"></i>
        </button>
        <button class="btn btn-sm btn-outline-danger btn-action" onclick="deleteItem(${item.id})" title="Supprimer">
          <i class="fas fa-trash"></i>
        </button>
      </td>
    `;
    
    tbody.appendChild(row);
  });

  // Initialisation de DataTable avec toutes les fonctionnalités
  $(document).ready(function() {
    const table = $('#mainTable').DataTable({
      // Pagination
      pageLength: 10,
      lengthMenu: [[5, 10, 25, 50, 100, -1], [5, 10, 25, 50, 100, "Tous"]],
      
      // Recherche
      searching: true,
      
      // Tri
      ordering: true,
      
      // Informations
      info: true,
      
      // État de sauvegarde
      stateSave: true,
      
      // Langue française
      language: {
        url: 'https://cdn.datatables.net/plug-ins/1.13.7/i18n/fr-FR.json'
      },
      
      // Extensions activées
      layout: {
        topStart: {
          buttons: [
            {
              extend: 'copy',
              text: '<i class="fas fa-copy me-1"></i>Copier',
              className: 'btn-sm'
            },
            {
              extend: 'csv',
              text: '<i class="fas fa-file-csv me-1"></i>CSV',
              className: 'btn-sm'
            },
            {
              extend: 'excel',
              text: '<i class="fas fa-file-excel me-1"></i>Excel',
              className: 'btn-sm'
            },
            {
              extend: 'pdf',
              text: '<i class="fas fa-file-pdf me-1"></i>PDF',
              className: 'btn-sm',
              orientation: 'landscape',
              pageSize: 'A4',
              exportOptions: {
                columns: [0, 1, 2, 4, 5, 6, 7, 8]
              }
            },
            {
              extend: 'print',
              text: '<i class="fas fa-print me-1"></i>Imprimer',
              className: 'btn-sm'
            },
            {
              extend: 'colvis',
              text: '<i class="fas fa-columns me-1"></i>Colonnes',
              className: 'btn-sm'
            }
          ]
        },
        topEnd: {
          search: {
            placeholder: 'Rechercher...'
          }
        }
      },
      
      // Configuration des colonnes
      columnDefs: [
        {
          targets: [8], // Colonne Statut
          searchPanes: {
            show: true
          }
        },
        {
          targets: [4], // Colonne Département
          searchPanes: {
            show: true
          }
        },
        {
          targets: [6], // Colonne Date
          type: 'date'
        },
        {
          targets: [7], // Colonne Salaire
          type: 'num'
        },
        {
          targets: [9], // Colonne Actions (non triable)
          orderable: false,
          searchable: false
        }
      ],
      
      // SearchPanes configuration
      searchPanes: {
        cascadePanes: true,
        viewTotal: true,
        layout: 'columns-4'
      },
      
      // Select extension
      select: {
        style: 'multi',
        selector: 'td:not(:last-child)'
      },
      
      // Responsive
      responsive: true,
      
      // AutoWidth
      autoWidth: true,
      
      // Scroll horizontal
      scrollX: true,
      
      // Initialisation terminée
      initComplete: function() {
        // Mise à jour des statistiques
        updateStats(this);
        
        // Écouteur pour mise à jour des stats
        this.on('search.dt order.dt page.dt length.dt', function() {
          updateStats(this);
        });
      }
    });
    
    // Filtres rapides
    $('.filter-quick').on('click', function() {
      const status = $(this).data('status');
      if (status === 'all') {
        table.column(8).search('').draw();
      } else {
        table.column(8).search(status).draw();
      }
      
      // Style actif
      $('.filter-quick').removeClass('active');
      $(this).addClass('active');
    });
    
    // Fonction de mise à jour des statistiques
    function updateStats(dataTable) {
      const info = dataTable.page.info();
      $('#totalRecords').text(info.recordsTotal);
      $('#filteredRecords').text(info.recordsDisplay);
      
      // Compter les filtres actifs
      let activeFilterCount = 0;
      const settings = dataTable.settings()[0];
      if (settings.oPreviousSearch.sSearch) activeFilterCount++;
      
      settings.aoPreSearchCols.forEach(col => {
        if (col.sSearch) activeFilterCount++;
      });
      
      $('#activeFilters').text(activeFilterCount);
    }
    
    // Exposer la table globalement
    window.dataTable = table;
  });

  // Fonctions d'action
  function viewItem(id) {
    const item = demoData.find(d => d.id === id);
    alert(`👤 ${item.name}\n📧 ${item.email}\n💼 ${item.position}\n🏢 ${item.department}\n💰 ${item.salary.toLocaleString('fr-FR')} €`);
  }

  function editItem(id) {
    const item = demoData.find(d => d.id === id);
    alert(`✏️ Modification de ${item.name}`);
  }

  function deleteItem(id) {
    const item = demoData.find(d => d.id === id);
    if (confirm(`⚠️ Supprimer ${item.name} ?`)) {
      alert(`✅ ${item.name} supprimé`);
    }
  }
</script>

</body>
</html>

Ouvrir cet aperçu dans un nouvel onglet du navigateur

🔗 Ouvrir dans le navigateur