About this snippet

A team members table with a search field, an add button, per row checkboxes and a theme switch. It is a real table element, so it stays readable to screen readers and pastes cleanly into a spreadsheet.

The header checkbox sets every row checkbox to match itself. Ticking rows one at a time walks the whole set and only leaves the header checked when all of them are, so the header never claims a state the rows below do not have.

Theming is a token swap. Every color is a CSS custom property, and a dark class on the body redefines that block, so one class flips the whole table and the toggle stays three lines of JavaScript. The table sits in a wrapper with overflow-x auto, so narrow screens scroll it sideways instead of crushing the columns. Search and sorting are not wired up yet, so treat the input as presentation for now.

Size
15.5 KB
Uses
HTML, CSS, JavaScript
Loads
placehold.co
Views
247
<div class="page-wrapper">
  
  <div class="table-widget">
    <div class="widget-header">
      <div class="header-titles">
        <h2>Team Members</h2>
        <p>Manage your team members and their account permissions here.</p>
      </div>
      
      <div class="header-actions">
        <div class="search-box">
          <svg class="search-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="11" cy="11" r="8"></circle>
            <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
          </svg>
          <input type="text" class="search-input" placeholder="Search members...">
        </div>
        
        <button class="theme-toggle" id="theme-btn" aria-label="Toggle Theme">
          <svg class="sun-icon" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="12" cy="12" r="5"></circle>
            <line x1="12" y1="1" x2="12" y2="3"></line>
            <line x1="12" y1="21" x2="12" y2="23"></line>
            <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
            <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
            <line x1="1" y1="12" x2="3" y2="12"></line>
            <line x1="21" y1="12" x2="23" y2="12"></line>
            <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
            <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
          </svg>
        </button>
        
        <button class="primary-btn">Add Member</button>
      </div>
    </div>
    
    <div class="table-container">
      <table class="data-table">
        <thead>
          <tr>
            <th class="cell-check">
              <input type="checkbox" class="cb-input" id="select-all">
            </th>
            <th>Name</th>
            <th>Title</th>
            <th>Status</th>
            <th>Last Active</th>
            <th class="cell-action"></th>
          </tr>
        </thead>
        <tbody>
          <!-- Row 1 -->
          <tr>
            <td class="cell-check">
              <input type="checkbox" class="cb-input row-checkbox">
            </td>
            <td>
              <div class="user-profile">
                <img src="https://placehold.co/40x40/3b82f6/ffffff?text=JS" alt="Avatar" class="avatar">
                <div class="user-info">
                  <span class="user-name">Jane Smith</span>
                  <span class="user-email">jane.smith@example.com</span>
                </div>
              </div>
            </td>
            <td>
              <div class="role-info">
                <span class="role-title">Lead Designer</span>
                <span class="role-dept">Product</span>
              </div>
            </td>
            <td>
              <span class="badge badge-active">Active</span>
            </td>
            <td class="text-muted">Just now</td>
            <td class="cell-action">
              <button class="action-btn">
                <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                  <circle cx="12" cy="12" r="2"></circle>
                  <circle cx="12" cy="5" r="2"></circle>
                  <circle cx="12" cy="19" r="2"></circle>
                </svg>
              </button>
            </td>
          </tr>
          
          <!-- Row 2 -->
          <tr>
            <td class="cell-check">
              <input type="checkbox" class="cb-input row-checkbox">
            </td>
            <td>
              <div class="user-profile">
                <img src="https://placehold.co/40x40/10b981/ffffff?text=MR" alt="Avatar" class="avatar">
                <div class="user-info">
                  <span class="user-name">Michael Ross</span>
                  <span class="user-email">michael.ross@example.com</span>
                </div>
              </div>
            </td>
            <td>
              <div class="role-info">
                <span class="role-title">Frontend Engineer</span>
                <span class="role-dept">Engineering</span>
              </div>
            </td>
            <td>
              <span class="badge badge-pending">In Review</span>
            </td>
            <td class="text-muted">2 hours ago</td>
            <td class="cell-action">
              <button class="action-btn">
                <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                  <circle cx="12" cy="12" r="2"></circle>
                  <circle cx="12" cy="5" r="2"></circle>
                  <circle cx="12" cy="19" r="2"></circle>
                </svg>
              </button>
            </td>
          </tr>
          
          <!-- Row 3 -->
          <tr>
            <td class="cell-check">
              <input type="checkbox" class="cb-input row-checkbox">
            </td>
            <td>
              <div class="user-profile">
                <img src="https://placehold.co/40x40/f59e0b/ffffff?text=ED" alt="Avatar" class="avatar">
                <div class="user-info">
                  <span class="user-name">Emma Davis</span>
                  <span class="user-email">emma.davis@example.com</span>
                </div>
              </div>
            </td>
            <td>
              <div class="role-info">
                <span class="role-title">Marketing Director</span>
                <span class="role-dept">Marketing</span>
              </div>
            </td>
            <td>
              <span class="badge badge-active">Active</span>
            </td>
            <td class="text-muted">Yesterday</td>
            <td class="cell-action">
              <button class="action-btn">
                <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                  <circle cx="12" cy="12" r="2"></circle>
                  <circle cx="12" cy="5" r="2"></circle>
                  <circle cx="12" cy="19" r="2"></circle>
                </svg>
              </button>
            </td>
          </tr>

          <!-- Row 4 -->
          <tr>
            <td class="cell-check">
              <input type="checkbox" class="cb-input row-checkbox">
            </td>
            <td>
              <div class="user-profile">
                <img src="https://placehold.co/40x40/ef4444/ffffff?text=WL" alt="Avatar" class="avatar">
                <div class="user-info">
                  <span class="user-name">William Lee</span>
                  <span class="user-email">will.lee@example.com</span>
                </div>
              </div>
            </td>
            <td>
              <div class="role-info">
                <span class="role-title">Data Analyst</span>
                <span class="role-dept">Data</span>
              </div>
            </td>
            <td>
              <span class="badge badge-offline">Offline</span>
            </td>
            <td class="text-muted">3 days ago</td>
            <td class="cell-action">
              <button class="action-btn">
                <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                  <circle cx="12" cy="12" r="2"></circle>
                  <circle cx="12" cy="5" r="2"></circle>
                  <circle cx="12" cy="19" r="2"></circle>
                </svg>
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    
    <div class="widget-footer">
      <p class="pagination-info">Showing 1 to 4 of 24 results</p>
      <div class="pagination">
        <button class="page-btn nav-btn" disabled>
          <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
        </button>
        <button class="page-btn active">1</button>
        <button class="page-btn">2</button>
        <button class="page-btn">3</button>
        <button class="page-btn nav-btn">
          <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
        </button>
      </div>
    </div>
  </div>
  
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

/* Base Light Theme */
:root {
  --page-bg: #f1f5f9;
  --card-bg: #ffffff;
  --text-main: #0f172a;
  --text-sub: #475569;
  --text-muted: #94a3b8;
  --border-color: #e2e8f0;
  --row-hover: #f8fafc;
  --primary-color: #3b82f6;
  --primary-hover: #2563eb;
  
  --badge-active-bg: #dcfce7;
  --badge-active-text: #166534;
  --badge-pending-bg: #fef3c7;
  --badge-pending-text: #92400e;
  --badge-offline-bg: #f1f5f9;
  --badge-offline-text: #475569;
}

/* Dark Theme Variant */
body.dark-theme {
  --page-bg: #020617;
  --card-bg: #0f172a;
  --text-main: #f8fafc;
  --text-sub: #cbd5e1;
  --text-muted: #64748b;
  --border-color: #1e293b;
  --row-hover: #1e293b;
  
  --badge-active-bg: rgba(22, 163, 74, 0.2);
  --badge-active-text: #4ade80;
  --badge-pending-bg: rgba(217, 119, 6, 0.2);
  --badge-pending-text: #fbbf24;
  --badge-offline-bg: rgba(71, 85, 105, 0.2);
  --badge-offline-text: #94a3b8;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  background: var(--page-bg);
  color: var(--text-main);
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 40px 20px;
  transition: background-color 0.3s ease, color 0.3s ease;
}

.page-wrapper {
  width: 100%;
  max-width: 1100px;
}

.table-widget {
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: 16px;
  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05);
  overflow: hidden;
  transition: background-color 0.3s ease, border-color 0.3s ease;
}

.widget-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 24px;
  border-bottom: 1px solid var(--border-color);
  flex-wrap: wrap;
  gap: 20px;
}

.header-titles h2 {
  margin: 0 0 8px 0;
  font-size: 1.25rem;
  font-weight: 600;
}

.header-titles p {
  margin: 0;
  color: var(--text-sub);
  font-size: 0.9rem;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

.search-box {
  position: relative;
  display: flex;
  align-items: center;
}

.search-icon {
  position: absolute;
  left: 12px;
  color: var(--text-muted);
}

.search-input {
  background: transparent;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 10px 10px 10px 40px;
  color: var(--text-main);
  font-size: 0.95rem;
  font-family: inherit;
  width: 250px;
  transition: border-color 0.2s ease;
}

.search-input:focus {
  outline: none;
  border-color: var(--primary-color);
}

.theme-toggle {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-main);
  border-radius: 8px;
  width: 42px;
  height: 42px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.theme-toggle:hover {
  background: var(--row-hover);
}

.primary-btn {
  background: var(--primary-color);
  color: #ffffff;
  border: none;
  border-radius: 8px;
  padding: 10px 20px;
  font-size: 0.95rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.primary-btn:hover {
  background: var(--primary-hover);
}

.table-container {
  width: 100%;
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 800px;
}

.data-table th, .data-table td {
  padding: 16px 24px;
  text-align: left;
  border-bottom: 1px solid var(--border-color);
}

.data-table th {
  background: var(--row-hover);
  color: var(--text-sub);
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  position: sticky;
  top: 0;
  z-index: 10;
}

.data-table tbody tr {
  transition: background-color 0.2s ease;
}

.data-table tbody tr:hover {
  background: var(--row-hover);
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.cell-check {
  width: 60px;
}

.cb-input {
  width: 18px;
  height: 18px;
  accent-color: var(--primary-color);
  cursor: pointer;
}

.user-profile {
  display: flex;
  align-items: center;
  gap: 16px;
}

.avatar {
  border-radius: 50%;
  object-fit: cover;
}

.user-info {
  display: flex;
  flex-direction: column;
}

.user-name {
  font-weight: 600;
  font-size: 1rem;
}

.user-email {
  color: var(--text-sub);
  font-size: 0.85rem;
  margin-top: 2px;
}

.role-info {
  display: flex;
  flex-direction: column;
}

.role-title {
  font-weight: 500;
}

.role-dept {
  color: var(--text-sub);
  font-size: 0.85rem;
  margin-top: 2px;
}

.badge {
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 0.8rem;
  font-weight: 600;
  display: inline-block;
}

.badge-active {
  background: var(--badge-active-bg);
  color: var(--badge-active-text);
}

.badge-pending {
  background: var(--badge-pending-bg);
  color: var(--badge-pending-text);
}

.badge-offline {
  background: var(--badge-offline-bg);
  color: var(--badge-offline-text);
}

.text-muted {
  color: var(--text-muted);
  font-size: 0.95rem;
}

.cell-action {
  text-align: right;
  width: 80px;
}

.action-btn {
  background: transparent;
  color: var(--text-muted);
  border: none;
  cursor: pointer;
  padding: 8px;
  border-radius: 6px;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: all 0.2s ease;
}

.action-btn:hover {
  background: var(--border-color);
  color: var(--text-main);
}

.widget-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px;
  border-top: 1px solid var(--border-color);
  flex-wrap: wrap;
  gap: 16px;
}

.pagination-info {
  margin: 0;
  color: var(--text-sub);
  font-size: 0.9rem;
}

.pagination {
  display: flex;
  gap: 8px;
}

.page-btn {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-main);
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  transition: all 0.2s ease;
}

.page-btn:hover:not(:disabled) {
  background: var(--row-hover);
}

.page-btn.active {
  background: var(--primary-color);
  color: #ffffff;
  border-color: var(--primary-color);
}

.page-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 768px) {
  .widget-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .header-actions {
    width: 100%;
    flex-wrap: wrap;
  }
  .search-input {
    width: 100%;
  }
  .search-box {
    flex-grow: 1;
  }
}
const themeBtn = document.getElementById("theme-btn");
const selectAllCheckbox = document.getElementById("select-all");
const rowCheckboxes = document.querySelectorAll(".row-checkbox");

// Toggle Light and Dark Mode
themeBtn.addEventListener("click", function() {
  document.body.classList.toggle("dark-theme");
});

// Logic for the Select All Checkbox
selectAllCheckbox.addEventListener("change", function(e) {
  const isChecked = e.target.checked;
  
  rowCheckboxes.forEach(function(checkbox) {
    checkbox.checked = isChecked;
  });
});

// Update the Select All Checkbox if individual rows are clicked
rowCheckboxes.forEach(function(checkbox) {
  checkbox.addEventListener("change", function() {
    let allChecked = true;
    
    rowCheckboxes.forEach(function(box) {
      if (!box.checked) {
        allChecked = false;
      }
    });
    
    selectAllCheckbox.checked = allChecked;
  });
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save