Skip to main content

Data Grid

<gstock-data-grid> | GstockDataGrid
<gstock-data-grid></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name' },
      { key: 'email', title: 'Email' },
      { key: 'role', title: 'Role' },
      { key: 'status', title: 'Status', align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      {
        id: 4,
        name: 'Ana Rodríguez',
        email: 'ana@example.com',
        role: 'User',
        status: 'Active',
      },
      { id: 5, name: 'Luis Martín', email: 'luis@example.com', role: 'Editor', status: 'Active' },
    ];
  });
</script>

Tamaño

Utilice el atributo size para cambiar el tamaño del data grid.

<gstock-data-grid size="small"></gstock-data-grid>
<gstock-data-grid size="medium"></gstock-data-grid>
<gstock-data-grid size="large"></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const gridSmall = document.querySelector('gstock-data-grid[size="small"]');
    const gridMedium = document.querySelector('gstock-data-grid[size="medium"]');
    const gridLarge = document.querySelector('gstock-data-grid[size="large"]');

    const columns = [
      { key: 'name', title: 'Name' },
      { key: 'role', title: 'Role' },
      { key: 'status', title: 'Status' },
    ];

    const data = [
      { id: 1, name: 'John Doe', role: 'Admin', status: 'Active' },
      { id: 2, name: 'Jane Smith', role: 'User', status: 'Active' },
      { id: 3, name: 'Mike Johnson', role: 'Editor', status: 'Inactive' },
    ];

    gridSmall.columns = columns;
    gridSmall.data = data;
    gridMedium.columns = columns;
    gridMedium.data = data;
    gridLarge.columns = columns;
    gridLarge.data = data;
  });
</script>

Columnas

Utilice JavaScript para configurar columnas y datos programáticamente.

<gstock-data-grid></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      {
        key: 'name',
        title: 'Full Name',
        sortable: true,
        width: '250px',
        align: 'left',
      },
      {
        key: 'email',
        title: 'Email Address',
        sortable: true,
        width: '250px',
        type: 'text',
      },
      {
        key: 'age',
        title: 'Age',
        sortable: true,
        width: '80px',
        align: 'center',
        type: 'number',
      },
      {
        key: 'active',
        title: 'Active',
        sortable: true,
        width: '150px',
        align: 'center',
        type: 'boolean',
        formatter: (value, row) => {
          return value ? '✅' : '❌';
        },
      },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Doe Smith',
        email: 'john.doe@company.com',
        age: 32,
        active: true,
      },
      {
        id: 2,
        name: 'Jane Marie Johnson',
        email: 'jane.johnson@company.com',
        age: 28,
        active: true,
      },
      {
        id: 3,
        name: 'Mike Brown Wilson',
        email: 'mike.brown@company.com',
        age: 35,

        active: false,
      },
      {
        id: 4,
        name: 'Sarah Davis Miller',
        email: 'sarah.davis@company.com',
        age: 30,

        active: true,
      },
      {
        id: 5,
        name: 'David Lee Taylor',
        email: 'david.lee@company.com',
        age: 26,
        active: true,
      },
    ];
  });
</script>

Rayado

Utilice el atributo striped para alternar los colores de fondo de las filas.

<gstock-data-grid striped></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name' },
      { key: 'email', title: 'Email' },
      { key: 'role', title: 'Role' },
      { key: 'status', title: 'Status', align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      { id: 4, name: 'Ana Rodríguez', email: 'ana@example.com', role: 'User', status: 'Active' },
      { id: 5, name: 'Luis Martín', email: 'luis@example.com', role: 'Editor', status: 'Active' },
    ];
  });
</script>

Con bordes

Utilice el atributo bordered para mostrar bordes en todas las celdas.

<gstock-data-grid bordered></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Product Name', sortable: true },
      { key: 'category', title: 'Category', sortable: true },
      { key: 'price', title: 'Price', sortable: true, align: 'right' },
      { key: 'inStock', title: 'In Stock', align: 'center' },
      { key: 'rating', title: 'Rating', sortable: true, align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'Wireless Headphones',
        category: 'Electronics',
        price: 99.99,
        inStock: true,
        rating: 4.5,
      },
      {
        id: 2,
        name: 'Coffee Maker',
        category: 'Appliances',
        price: 129.99,
        inStock: false,
        rating: 4.2,
      },
      {
        id: 3,
        name: 'Yoga Mat',
        category: 'Fitness',
        price: 29.99,
        inStock: true,
        rating: 4.7,
      },
      {
        id: 4,
        name: 'Smartphone',
        category: 'Electronics',
        price: 699.99,
        inStock: true,
        rating: 4.3,
      },
      {
        id: 5,
        name: 'Running Shoes',
        category: 'Sports',
        price: 89.99,
        inStock: false,
        rating: 4.1,
      },
      { id: 6, name: 'Desk Lamp', category: 'Home', price: 39.99, inStock: true, rating: 4.0 },
      { id: 7, name: 'Backpack', category: 'Travel', price: 59.99, inStock: true, rating: 4.4 },
      {
        id: 8,
        name: 'Water Bottle',
        category: 'Sports',
        price: 19.99,
        inStock: true,
        rating: 4.6,
      },
    ];
  });
</script>

Efecto hover

Utilice el atributo hoverable para agregar efectos de hover en las filas.

<gstock-data-grid hoverable></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      {
        id: 4,
        name: 'Ana Rodríguez',
        email: 'ana@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 5,
        name: 'Luis Martín',
        email: 'luis@example.com',
        role: 'Editor',
        status: 'Active',
      },
    ];
  });
</script>

Compacto

Utilice el atributo compact para mostrar el data grid con un diseño más compacto.

<gstock-data-grid size="small" compact></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    // Configure columns
    grid.columns = [
      { key: 'id', title: 'ID', sortable: true, width: '60px' },
      { key: 'code', title: 'Code', sortable: true, width: '100px' },
      { key: 'name', title: 'Item Name', sortable: true },
      {
        key: 'quantity',
        title: 'Qty',
        sortable: true,
        type: 'number',
        align: 'center',
        width: '80px',
      },
      { key: 'unit', title: 'Unit', sortable: true, width: '80px' },
      {
        key: 'price',
        title: 'Price',
        sortable: true,
        type: 'currency',
        align: 'center',
        width: '100px',
      },
      {
        key: 'total',
        title: 'Total',
        sortable: true,
        type: 'currency',
        align: 'center',
        width: '100px',
      },
      {
        key: 'status',
        title: 'Status',
        sortable: true,
        width: '150px',
      },
    ];

    const sampleData = [
      {
        id: 1,
        code: 'ITM001',
        name: 'Widget A',
        quantity: 25,
        unit: 'pcs',
        price: 12.5,
        total: 312.5,
        status: 'Active',
      },
      {
        id: 2,
        code: 'ITM002',
        name: 'Component B',
        quantity: 50,
        unit: 'pcs',
        price: 8.75,
        total: 437.5,
        status: 'Active',
      },
      {
        id: 3,
        code: 'ITM003',
        name: 'Part C',
        quantity: 100,
        unit: 'pcs',
        price: 3.2,
        total: 320.0,
        status: 'Low Stock',
      },
      {
        id: 4,
        code: 'ITM004',
        name: 'Assembly D',
        quantity: 15,
        unit: 'sets',
        price: 45.0,
        total: 675.0,
        status: 'Active',
      },
      {
        id: 5,
        code: 'ITM005',
        name: 'Tool E',
        quantity: 8,
        unit: 'pcs',
        price: 125.0,
        total: 1000.0,
        status: 'Active',
      },
      {
        id: 6,
        code: 'ITM006',
        name: 'Material F',
        quantity: 200,
        unit: 'kg',
        price: 2.25,
        total: 450.0,
        status: 'Active',
      },
      {
        id: 7,
        code: 'ITM007',
        name: 'Equipment G',
        quantity: 3,
        unit: 'units',
        price: 850.0,
        total: 2550.0,
        status: 'Reserved',
      },
      {
        id: 8,
        code: 'ITM008',
        name: 'Supply H',
        quantity: 75,
        unit: 'boxes',
        price: 15.6,
        total: 1170.0,
        status: 'Active',
      },
      {
        id: 9,
        code: 'ITM009',
        name: 'Kit I',
        quantity: 12,
        unit: 'sets',
        price: 78.9,
        total: 946.8,
        status: 'Discontinued',
      },
      {
        id: 10,
        code: 'ITM010',
        name: 'Module J',
        quantity: 30,
        unit: 'pcs',
        price: 28.4,
        total: 852.0,
        status: 'Active',
      },
    ];

    grid.data = sampleData;
  });
</script>

Seleccionable

Utilice el atributo selectable para habilitar la selección de una sola fila con casillas de verificación. Solo se puede seleccionar una fila a la vez.

Clear Selection Action on Selected
Selected: 0 rows
<div class="selection-actions">
  <gstock-button id="clear-selection-btn" color="secondary" variant="outlined">
    Clear Selection
  </gstock-button>
  <gstock-button id="perform-action-btn" color="primary">Action on Selected</gstock-button>
</div>

<div class="selection-info">
  <div id="selection-info">Selected: <strong>0</strong> rows</div>
</div>

<gstock-data-grid selectable></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const selectionInfo = document.querySelector('#selection-info');
    const clearSelectionBtn = document.querySelector('#clear-selection-btn');
    const performActionBtn = document.querySelector('#perform-action-btn');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      {
        id: 4,
        name: 'Ana Rodríguez',
        email: 'ana@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 5,
        name: 'Luis Martín',
        email: 'luis@example.com',
        role: 'Editor',
        status: 'Active',
      },
    ];

    grid.addEventListener('gstock-data-grid-selection-change-event', e => {
      updateSelectionInfo();
    });

    function updateSelectionInfo() {
      const selectedRows = grid.getSelectedRows();
      const count = selectedRows.length;
      selectionInfo.innerHTML = `Selected: <strong>${count}</strong> ${count === 1 ? 'row' : 'rows'}`;
    }

    function clearSelection() {
      grid.deselectAll();
    }

    function performAction() {
      const selectedRows = grid.getSelectedRows();
      if (selectedRows.length === 0) {
        alert('Please select one row to perform an action.');
        return;
      }

      const selectedRow = selectedRows[0]; // Only one row should be selected
      alert(`Action performed on: ${selectedRow.name}`);
    }

    clearSelectionBtn.addEventListener('click', clearSelection);
    performActionBtn.addEventListener('click', performAction);

    updateSelectionInfo();
  });
</script>

<style>
  .selection-info {
    background: #f8f9fa;
    padding: 1rem;
    border-radius: 4px;
    margin: 1rem 0;
    border-left: 4px solid #007bff;
    font-size: 14px;
  }

  .selection-actions {
    margin: 1rem 0;
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
  }

  .selection-actions button {
    padding: 0.5rem 1rem;
    border: 1px solid #ddd;
    background: white;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
  }

  .selection-actions button:hover {
    background: #f8f9fa;
  }

  .selection-actions button.primary {
    background: #007bff;
    color: white;
    border-color: #007bff;
  }

  .selection-actions button.primary:hover {
    background: #0056b3;
  }
</style>

Multi-selección

Combine los atributos selectable y multi-select para permitir la selección de varias filas. Aparecerá un checkbox en el encabezado para seleccionar o deseleccionar todas las filas.

Select All Clear Selection Action on Selected
Selected: 0 rows
<div class="selection-actions">
  <gstock-button id="select-all-btn" color="secondary" variant="outlined">
    Select All
  </gstock-button>
  <gstock-button id="clear-selection-btn" color="secondary" variant="outlined">
    Clear Selection
  </gstock-button>
  <gstock-button id="perform-action-btn" color="primary" disabled>Action on Selected</gstock-button>
</div>

<div class="selection-info">
  <div id="selection-info">Selected: <strong>0</strong> rows</div>
</div>

<gstock-data-grid selectable multi-select></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const selectionInfo = document.querySelector('#selection-info');
    const selectAllBtn = document.querySelector('#select-all-btn');
    const clearSelectionBtn = document.querySelector('#clear-selection-btn');
    const performActionBtn = document.querySelector('#perform-action-btn');

    grid.columns = [
      { key: 'name', title: 'Name' },
      { key: 'email', title: 'Email' },
      { key: 'role', title: 'Role' },
      { key: 'status', title: 'Status', align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Doe',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Jane Smith',
        email: 'jane@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Mike Johnson',
        email: 'mike@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      { id: 4, name: 'Sarah Wilson', email: 'sarah@example.com', role: 'User', status: 'Active' },
      { id: 5, name: 'David Brown', email: 'david@example.com', role: 'Editor', status: 'Active' },
    ];

    // Listen for selection changes
    grid.addEventListener('gstock-data-grid-selection-change-event', event => {
      const selectedCount = event.detail.selectedData.length;
      selectionInfo.innerHTML = `Selected: <strong>${selectedCount}</strong> rows`;
      console.log('Selected rows:', event.detail.selectedData);
    });

    // Button event handlers
    selectAllBtn.addEventListener('click', () => {
      grid.selectAll();
      console.log('Select All clicked');
    });

    clearSelectionBtn.addEventListener('click', () => {
      grid.deselectAll();
    });

    performActionBtn.addEventListener('click', () => {
      const selected = grid.getSelectedRows();
      if (selected.length > 0) {
        alert(
          `Performing action on ${selected.length} selected rows:\n${selected.map(row => row.name).join(', ')}`,
        );
      } else {
        alert('No rows selected');
      }
    });
  });
</script>

<style>
  .selection-actions {
    margin-bottom: 1rem;
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
  }

  .selection-info {
    margin-bottom: 1rem;
    padding: 0.5rem;
    background-color: var(--gstock-color-neutral-50);
    border: 1px solid var(--gstock-color-neutral-200);
    border-radius: var(--gstock-border-radius-medium);
  }

  #selection-info {
    margin: 0;
    font-size: var(--gstock-legacy-font-size-small);
  }
</style>

Ordenable

Utilice el atributo sortable para habilitar la funcionalidad de ordenamiento de columnas.

<gstock-data-grid sortable></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
      { key: 'lastLogin', title: 'Last Login', sortable: true, type: 'date' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
        lastLogin: '2024-01-15',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
        lastLogin: '2024-01-14',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
        lastLogin: '2024-01-10',
      },
      {
        id: 4,
        name: 'Ana Rodríguez',
        email: 'ana@example.com',
        role: 'User',
        status: 'Active',
        lastLogin: '2024-01-16',
      },
      {
        id: 5,
        name: 'Luis Martín',
        email: 'luis@example.com',
        role: 'Editor',
        status: 'Active',
        lastLogin: '2024-01-12',
      },
    ];

    // Listen for sort changes
    grid.addEventListener('gstock-sort-change', event => {
      console.log('Sort changed:', event.detail);
    });
  });
</script>

Filtrable

Utilice el atributo filterable para habilitar el filtrado de columnas.

All Departments Engineering Marketing Sales HR Finance
Apply Filters Clear All
Showing all 12 records
<div class="filter-controls">
  <div class="filter-group">
    <gstock-input
      type="text"
      id="name-filter"
      label="Name Filter"
      placeholder="Search by name..."></gstock-input>
  </div>

  <div class="filter-group">
    <gstock-select id="department-filter" label="Department">
      <gstock-option value="">All Departments</gstock-option>
      <gstock-option value="Engineering">Engineering</gstock-option>
      <gstock-option value="Marketing">Marketing</gstock-option>
      <gstock-option value="Sales">Sales</gstock-option>
      <gstock-option value="HR">HR</gstock-option>
      <gstock-option value="Finance">Finance</gstock-option>
    </gstock-select>
  </div>

  <div class="filter-group">
    <gstock-input
      type="number"
      id="salary-min"
      placeholder="0"
      min="0"
      step="1000"
      label="Min Salary"></gstock-input>
  </div>

  <div class="filter-group">
    <gstock-input
      type="number"
      id="salary-max"
      placeholder="200000"
      min="0"
      step="1000"
      label="Max Salary"></gstock-input>
  </div>

  <div class="filter-actions">
    <gstock-button id="apply-filters-btn" class="primary">Apply Filters</gstock-button>
    <gstock-button id="clear-filters-btn">Clear All</gstock-button>
  </div>
</div>

<div class="filter-status" id="filter-status">Showing all 12 records</div>

<gstock-data-grid filterable></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const filterStatus = document.querySelector('#filter-status');
    const applyFiltersBtn = document.querySelector('#apply-filters-btn');
    const clearFiltersBtn = document.querySelector('#clear-filters-btn');

    // Configure columns
    grid.columns = [
      { key: 'id', title: 'ID', sortable: true, width: '60px' },
      { key: 'name', title: 'Employee Name', sortable: true, filterable: true },
      { key: 'department', title: 'Department', sortable: true, filterable: true },
      { key: 'position', title: 'Position', sortable: true },
      { key: 'salary', title: 'Salary', sortable: true, align: 'right' },
      { key: 'startDate', title: 'Start Date', sortable: true, type: 'date' },
      { key: 'email', title: 'Email', sortable: true, filterable: true },
    ];

    const originalData = [
      {
        id: 1,
        name: 'John Smith',
        department: 'Engineering',
        position: 'Software Engineer',
        salary: 85000,
        startDate: '2023-01-15',
        email: 'john.smith@company.com',
      },
      {
        id: 2,
        name: 'Sarah Johnson',
        department: 'Marketing',
        position: 'Marketing Manager',
        salary: 75000,
        startDate: '2022-11-20',
        email: 'sarah.johnson@company.com',
      },
      {
        id: 3,
        name: 'Mike Davis',
        department: 'Sales',
        position: 'Sales Representative',
        salary: 55000,
        startDate: '2023-03-10',
        email: 'mike.davis@company.com',
      },
      {
        id: 4,
        name: 'Emily Chen',
        department: 'Engineering',
        position: 'Senior Developer',
        salary: 95000,
        startDate: '2021-09-05',
        email: 'emily.chen@company.com',
      },
      {
        id: 5,
        name: 'David Wilson',
        department: 'HR',
        position: 'HR Specialist',
        salary: 60000,
        startDate: '2022-07-12',
        email: 'david.wilson@company.com',
      },
      {
        id: 6,
        name: 'Lisa Anderson',
        department: 'Finance',
        position: 'Financial Analyst',
        salary: 70000,
        startDate: '2023-02-28',
        email: 'lisa.anderson@company.com',
      },
      {
        id: 7,
        name: 'Chris Taylor',
        department: 'Engineering',
        position: 'DevOps Engineer',
        salary: 88000,
        startDate: '2022-12-01',
        email: 'chris.taylor@company.com',
      },
      {
        id: 8,
        name: 'Amanda Brown',
        department: 'Marketing',
        position: 'Content Specialist',
        salary: 52000,
        startDate: '2023-04-18',
        email: 'amanda.brown@company.com',
      },
      {
        id: 9,
        name: 'Robert Lee',
        department: 'Sales',
        position: 'Sales Manager',
        salary: 82000,
        startDate: '2021-08-30',
        email: 'robert.lee@company.com',
      },
      {
        id: 10,
        name: 'Jennifer White',
        department: 'Finance',
        position: 'Senior Accountant',
        salary: 78000,
        startDate: '2022-05-15',
        email: 'jennifer.white@company.com',
      },
      {
        id: 11,
        name: 'Kevin Martinez',
        department: 'Engineering',
        position: 'Tech Lead',
        salary: 105000,
        startDate: '2020-11-12',
        email: 'kevin.martinez@company.com',
      },
      {
        id: 12,
        name: 'Michelle Garcia',
        department: 'HR',
        position: 'HR Manager',
        salary: 85000,
        startDate: '2021-06-08',
        email: 'michelle.garcia@company.com',
      },
    ];

    grid.data = originalData;

    grid.addEventListener('gstock-filter-change', e => {
      updateFilterStatus();
    });

    function applyFilters() {
      const nameFilter = document.querySelector('#name-filter').value.toLowerCase();
      const departmentFilter = document.querySelector('#department-filter').value;
      const salaryMin = parseInt(document.querySelector('#salary-min').value) || 0;
      const salaryMax = parseInt(document.querySelector('#salary-max').value) || Infinity;

      let filteredData = originalData.filter(item => {
        const nameMatch = !nameFilter || item.name.toLowerCase().includes(nameFilter);
        const departmentMatch = !departmentFilter || item.department === departmentFilter;
        const salaryMatch = item.salary >= salaryMin && item.salary <= salaryMax;

        return nameMatch && departmentMatch && salaryMatch;
      });

      grid.data = filteredData;
      updateFilterStatus();
    }

    function clearFilters() {
      document.querySelector('#name-filter').value = '';
      document.querySelector('#department-filter').value = '';
      document.querySelector('#salary-min').value = '';
      document.querySelector('#salary-max').value = '';

      grid.data = originalData;
      grid.clearFilters();
      updateFilterStatus();
    }

    function updateFilterStatus() {
      const currentData = grid.data || [];
      const total = originalData.length;
      const showing = currentData.length;

      if (showing === total) {
        filterStatus.textContent = `Showing all ${total} records`;
      } else {
        filterStatus.textContent = `Showing ${showing} of ${total} records (filtered)`;
      }
    }

    applyFiltersBtn.addEventListener('click', applyFilters);
    clearFiltersBtn.addEventListener('click', clearFilters);

    document.querySelector('#name-filter').addEventListener('input', applyFilters);
    document.querySelector('#department-filter').addEventListener('change', applyFilters);
    document.querySelector('#salary-min').addEventListener('input', applyFilters);
    document.querySelector('#salary-max').addEventListener('input', applyFilters);

    updateFilterStatus();
  });
</script>

<style>
  .filter-controls {
    background: #f8f9fa;
    padding: 1rem;
    border-radius: 4px;
    margin: 1rem 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
  }

  .filter-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .filter-group label {
    font-weight: 600;
    font-size: 14px;
    color: #333;
  }

  .filter-group input,
  .filter-group select {
    padding: 0.5rem;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
  }

  .filter-actions {
    display: flex;
    gap: 0.5rem;
    align-items: end;
  }

  .filter-actions button {
    padding: 0.5rem 1rem;
    border: 1px solid #ddd;
    background: white;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    height: fit-content;
  }

  .filter-actions button:hover {
    background: #f8f9fa;
  }

  .filter-actions button.primary {
    background: #007bff;
    color: white;
    border-color: #007bff;
  }

  .filter-actions button.primary:hover {
    background: #0056b3;
  }

  .filter-status {
    margin: 1rem 0;
    padding: 0.5rem;
    background: #e3f2fd;
    border-radius: 4px;
    font-size: 14px;
  }
</style>

Paginación

Utilice el atributo paginated para habilitar paginación virtual para datasets.

<gstock-data-grid paginated page-size="3"></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
    ];

    grid.data = [
      {
        id: 1,
        name: 'John Doe',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Jane Smith',
        email: 'jane@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Mike Johnson',
        email: 'mike@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      { id: 4, name: 'Sarah Wilson', email: 'sarah@example.com', role: 'User', status: 'Active' },
      { id: 5, name: 'David Brown', email: 'david@example.com', role: 'Editor', status: 'Active' },
      { id: 6, name: 'Emily Davis', email: 'emily@example.com', role: 'User', status: 'Active' },
      {
        id: 7,
        name: 'Michael Miller',
        email: 'michael@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 8,
        name: 'Laura Taylor',
        email: 'laura@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
      {
        id: 9,
        name: 'Robert Anderson',
        email: 'robert@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 10,
        name: 'Jessica Thompson',
        email: 'jessica@example.com',
        role: 'Editor',
        status: 'Active',
      },
    ];
  });
</script>

Combine los atributos paginated junto a los atributos total-pages y total-items para utilizar paginación del servidor y cargar datos bajo demanda.

<gstock-data-grid
  paginated
  page-size="5"
  current-page="1"
  total-pages="10"
  total-items="50"></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'id', title: 'ID', sortable: true, width: '80px' },
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'department', title: 'Department', sortable: true },
      { key: 'joinDate', title: 'Join Date', sortable: true, align: 'center' },
    ];

    function loadPageData(page, isInitialLoad = false) {
      if (isInitialLoad) {
        grid.loading = true;
      }

      setTimeout(() => {
        const pageData = [];
        const startId = (page - 1) * 5 + 1;

        for (let i = 0; i < 5; i++) {
          const id = startId + i;
          pageData.push({
            id: id,
            name: `Employee ${id}`,
            email: `employee${id}@company.com`,
            department: ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance'][id % 5],
            joinDate: `2023-${String(Math.floor(Math.random() * 12) + 1).padStart(2, '0')}-${String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}`,
          });
        }

        grid.data = pageData;
        grid.loading = false;
      }, 500);
    }

    grid.addEventListener('gstock-page-change-event', event => {
      loadPageData(event.detail.currentPage, false);
    });

    loadPageData(1, true);
  });
</script>

Redimensionable

Utilice el atributo resizable para habilitar la función de redimensionamiento de columnas.

<gstock-data-grid resizable bordered hoverable></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    // Configure columns with different resizable settings
    grid.columns = [
      {
        key: 'id',
        title: 'ID',
        width: '60px',
        resizable: true,
        sortable: true,
      },
      {
        key: 'name',
        title: 'Product Name',
        resizable: true,
        sortable: true,
      },
      {
        key: 'category',
        title: 'Category',
        width: '200px',
        resizable: true,
        sortable: true,
      },
      {
        key: 'price',
        title: 'Price',
        width: '150px',
        align: 'right',
        resizable: true,
        sortable: true,
        formatter: value => `${parseFloat(value).toFixed(2)}`,
      },
      {
        key: 'stock',
        title: 'Stock',
        width: '150px',
        align: 'center',
        resizable: true,
        sortable: true,
      },
      {
        key: 'status',
        title: 'Status',
        width: '200px',
        align: 'center',
        resizable: false, // This column cannot be resized
        formatter: value => {
          const color =
            value === 'Available' ? 'success' : value === 'Low Stock' ? 'warning' : 'danger';
          return `<gstock-badge color="${color}">${value}</gstock-badge>`;
        },
      },
    ];

    // Sample data
    grid.data = [
      {
        id: 1,
        name: 'Laptop Dell XPS 13',
        category: 'Electronics',
        price: 999.99,
        stock: 15,
        status: 'Available',
      },
      {
        id: 2,
        name: 'Wireless Mouse Logitech',
        category: 'Accessories',
        price: 29.99,
        stock: 3,
        status: 'Low Stock',
      },
      {
        id: 3,
        name: 'Mechanical Keyboard',
        category: 'Accessories',
        price: 79.99,
        stock: 0,
        status: 'Out of Stock',
      },
      {
        id: 4,
        name: 'Monitor 4K Samsung',
        category: 'Electronics',
        price: 349.99,
        stock: 8,
        status: 'Available',
      },
      {
        id: 5,
        name: 'USB-C Hub',
        category: 'Accessories',
        price: 49.99,
        stock: 12,
        status: 'Available',
      },
      {
        id: 6,
        name: 'Webcam HD',
        category: 'Electronics',
        price: 89.99,
        stock: 2,
        status: 'Low Stock',
      },
    ];

    // Listen for column resize events
    grid.addEventListener('gstock-data-grid-column-resize-event', event => {
      console.log('Column resized:', {
        column: event.detail.column,
        newWidth: event.detail.width,
        allColumnWidths: event.detail.columnWidths,
      });
    });
  });
</script>

Estado de carga

Utilice el atributo loading para mostrar un indicador de carga. Mientras el estado de carga está activo, se muestra un mensaje indicando el estado.

Load Data Slow Load (3s ) Simulate Error Clear Data
Ready to load data
<div class="demo-controls">
  <gstock-button id="load-data-btn" color="primary">Load Data</gstock-button>
  <gstock-button id="slow-load-btn" color="secondary" variant="outlined">
    Slow Load (3s )</gstock-button
  >
  <gstock-button id="simulate-error-btn" color="secondary" variant="outlined">
    Simulate Error
  </gstock-button>
  <gstock-button id="clear-data-btn" color="secondary" variant="outlined">Clear Data</gstock-button>
</div>

<div class="status-indicator" id="status-indicator">Ready to load data</div>

<gstock-data-grid loading></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const statusIndicator = document.querySelector('#status-indicator');
    const loadDataBtn = document.querySelector('#load-data-btn');
    const slowLoadBtn = document.querySelector('#slow-load-btn');
    const simulateErrorBtn = document.querySelector('#simulate-error-btn');
    const clearDataBtn = document.querySelector('#clear-data-btn');

    grid.columns = [
      { key: 'id', title: 'ID', sortable: true, width: '80px' },
      { key: 'title', title: 'Title', sortable: true },
      { key: 'author', title: 'Author', sortable: true },
      { key: 'category', title: 'Category', sortable: true },
      { key: 'publishDate', title: 'Date', sortable: true, type: 'date' },
    ];

    const sampleData = [
      {
        id: 1,
        title: 'Introduction to Web Components',
        author: 'John Pérez',
        category: 'Technology',
        publishDate: '2024-01-15',
      },
      {
        id: 2,
        title: 'CSS Best Practices',
        author: 'Mary García',
        category: 'Design',
        publishDate: '2024-01-14',
      },
      {
        id: 3,
        title: 'Modern JavaScript',
        author: 'Charles López',
        category: 'Programming',
        publishDate: '2024-01-13',
      },
      {
        id: 4,
        title: 'UX/UI Design Principles',
        author: 'Ana Rodríguez',
        category: 'Design',
        publishDate: '2024-01-12',
      },
      {
        id: 5,
        title: 'Performance Optimization',
        author: 'Luis Martín',
        category: 'Technology',
        publishDate: '2024-01-11',
      },
    ];

    function updateStatus(message, type = '') {
      statusIndicator.textContent = message;
      statusIndicator.className = `status-indicator ${type}`;
    }

    function loadData() {
      grid.loading = true;
      updateStatus('Loading data...', 'loading');

      setTimeout(() => {
        grid.data = sampleData;
        grid.loading = false;
        updateStatus('Data loaded successfully', 'loaded');
      }, 1000);
    }

    function simulateSlowLoad() {
      grid.loading = true;
      updateStatus('Loading data (slow)...', 'loading');

      setTimeout(() => {
        grid.data = sampleData;
        grid.loading = false;
        updateStatus('Data loaded after 3 seconds', 'loaded');
      }, 3000);
    }

    function simulateError() {
      grid.loading = true;
      updateStatus('Trying to load data...', 'loading');

      setTimeout(() => {
        grid.loading = false;
        grid.data = [];
        updateStatus('Error loading data', 'error');
      }, 2000);
    }

    function clearData() {
      grid.data = [];
      grid.loading = false;
      updateStatus('Data cleared', '');
    }

    loadDataBtn.addEventListener('click', loadData);
    slowLoadBtn.addEventListener('click', simulateSlowLoad);
    simulateErrorBtn.addEventListener('click', simulateError);
    clearDataBtn.addEventListener('click', clearData);

    updateStatus('Ready to load data', '');
  });
</script>

<style>
  .status-indicator {
    margin: 1rem 0;
    padding: 0.75rem;
    border-radius: 4px;
    font-weight: 500;
  }

  .status-indicator.loading {
    background: #fff3cd;
    color: #856404;
    border: 1px solid #ffeaa7;
  }

  .status-indicator.loaded {
    background: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
  }

  .status-indicator.error {
    background: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
  }
</style>

Utilice el atributo loading-message para personalizar el mensaje del estado de carga.

<gstock-data-grid loading-message="Custom loading message..." loading></gstock-data-grid>

Estado vacío

El data grid muestra un mensaje indicando el estado cuando no hay datos disponibles.

Add Data Clear Data
<div class="demo-controls">
  <gstock-button id="add-data-btn" color="primary">Add Data</gstock-button>
  <gstock-button id="clear-data-btn" color="secondary" variant="outlined">
    Clear Data
  </gstock-button>
</div>

<gstock-data-grid></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const addDataBtn = document.querySelector('#add-data-btn');
    const clearDataBtn = document.querySelector('#clear-data-btn');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
    ];

    grid.data = [];

    const sampleData = [
      {
        id: 1,
        name: 'John Pérez',
        email: 'john@example.com',
        role: 'Administrator',
        status: 'Active',
      },
      {
        id: 2,
        name: 'Mary García',
        email: 'mary@example.com',
        role: 'User',
        status: 'Active',
      },
      {
        id: 3,
        name: 'Charles López',
        email: 'charles@example.com',
        role: 'Editor',
        status: 'Inactive',
      },
    ];

    function addData() {
      grid.data = [...sampleData];
      console.log('Data added:', grid.data.length, 'records');
    }

    function clearData() {
      grid.data = [];
      console.log('Data cleared, current records:', grid.data.length);
      if (grid.requestUpdate) {
        grid.requestUpdate();
      }
    }

    addDataBtn.addEventListener('click', addData);
    clearDataBtn.addEventListener('click', clearData);
  });
</script>

Utilice el atributo empty-message para personalizar el mensaje del estado vacío.

<gstock-data-grid empty-message="Custom empty message"></gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true },
      { key: 'email', title: 'Email', sortable: true },
      { key: 'role', title: 'Role', sortable: true },
      { key: 'status', title: 'Status', sortable: true, align: 'center' },
    ];

    grid.data = [];
  });
</script>

Avanzado

Combine múltiples características para una experiencia completa del data grid.

User Management

Export Add User
Last updated: June 2, 2025 0 items selected
<gstock-data-grid
  striped
  hoverable
  selectable
  multi-select
  sortable
  filterable
  paginated
  page-size="5">
  <div slot="toolbar">
    <div style="display: flex; justify-content: space-between; align-items: center">
      <h3 style="margin: 0">User Management</h3>
      <div style="display: flex; gap: 8px">
        <gstock-button prefix="download" variant="plain" id="export-btn"> Export </gstock-button>
        <gstock-button prefix="plus" id="add-btn"> Add User </gstock-button>
      </div>
    </div>
  </div>

  <div slot="footer">
    <div
      style="
        display: flex;
        justify-content: space-between;
        align-items: center;
        font-size: 0.875rem;
        color: var(--gstock-legacy-color-grayscale-600);
      ">
      <span>Last updated: June 2, 2025</span>
      <span id="selection-info">0 items selected</span>
    </div>
  </div>
</gstock-data-grid>

<script type="module">
  customElements.whenDefined('gstock-data-grid').then(() => {
    
    const grid = document.querySelector('gstock-data-grid');
    const selectionInfo = document.querySelector('#selection-info');
    const exportBtn = document.querySelector('#export-btn');
    const addBtn = document.querySelector('#add-btn');

    grid.columns = [
      { key: 'name', title: 'Name', sortable: true, filterable: true },
      { key: 'email', title: 'Email', sortable: true, filterable: true },
      {
        key: 'role',
        title: 'Role',
        sortable: true,
        filterable: true,
        formatter: (value, row) => {
          const color =
            value === 'Administrator' ? 'primary' : value === 'Editor' ? 'warning' : 'neutral';
          return `<gstock-badge color="${color}">${value}</gstock-badge>`;
        },
      },
      {
        key: 'status',
        title: 'Status',
        align: 'center',
        sortable: true,
        filterable: true,
        formatter: (value, row) => {
          const color = value === 'Active' ? 'success' : 'danger';
          const icon = value === 'Active' ? 'check-circle' : 'x-circle';
          return `<gstock-icon name="${icon}" style="color: var(--gstock-color-semantic-${color}-500);"></gstock-icon>`;
        },
      },
      { key: 'lastLogin', title: 'Last Login', sortable: true, type: 'date' },
      {
        key: 'actions',
        title: 'Actions',
        align: 'center',
        formatter: (value, row) => {
          return `
          <div style="display: flex; gap: 4px; justify-content: center;">
            <gstock-icon-button icon="edit" size="small" variant="outlined" title="Edit">
            </gstock-icon-button>
            <gstock-icon-button icon="trash" size="small" variant="outlined" color="danger" title="Delete">
            </gstock-icon-button>
          </div>
        `;
        },
      },
    ];

    // Generate larger dataset
    const roles = ['Administrator', 'User', 'Editor'];
    const statuses = ['Active', 'Inactive'];
    const names = [
      'John Pérez',
      'Mary García',
      'Charles López',
      'Ana Rodríguez',
      'Luis Martín',
      'Elena Ruiz',
      'Miguel Sánchez',
      'Laura Torres',
      'David Herrera',
      'Carmen Vega',
      'Pedro Morales',
      'Sofia Castillo',
      'Alejandro Ramos',
      'Isabel Jiménez',
      'Roberto Silva',
    ];

    grid.data = names.map((name, index) => ({
      id: index + 1,
      name,
      email: `${name.toLowerCase().replace(' ', '.')}@example.com`,
      role: roles[index % roles.length],
      status: statuses[index % statuses.length],
      lastLogin: new Date(2024, 0, 15 - (index % 10)).toISOString().split('T')[0],
    }));

    grid.addEventListener('gstock-data-grid-selection-change-event', event => {
      const count = event.detail.selectedData.length;
      selectionInfo.textContent = `${count} item${count !== 1 ? 's' : ''} selected`;
    });

    exportBtn.addEventListener('click', () => {
      const selectedData = grid.getSelectedRows();
      console.log('Exporting data:', selectedData.length ? selectedData : grid.data);
      alert(`Exporting ${selectedData.length ? selectedData.length : grid.data.length} records...`);
    });

    addBtn.addEventListener('click', () => {
      alert('Open form to add new user...');
    });

    grid.addEventListener('gstock-row-click', event => {
      console.log('Row clicked:', event.detail.row);
    });

    grid.addEventListener('gstock-sort-change', event => {
      console.log('Sort changed:', event.detail);
    });
  });
</script>