Data Grids

There are two main types of tables:

  1. Interactive Tables: Users can interact with these tables by performing actions such as selecting and editing.
  2. Read-Only Tables: These tables display data without allowing any modifications or interactions.

Structure and Layout

The following specifications apply to both interactive and read-only tables.

Columns

Rows

Alignment

Table structure image

Responsive Design

Read-only Tables

Read-only tables serve as static displays of information where users can view data without the ability to interact directly with or modify it.

No hover effects are applied to read-only tables; because users cannot interact with the data, and hover effects might give a false impression of interactivity.

Title Names Numbers Dates Chips
Title here SURNAME, Name 12345 dd mmm yyyy
New
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
error
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
error
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
error
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
Title here SURNAME, Name 12345 dd mmm yyyy
Modified
Title here SURNAME, Name 12345 dd mmm yyyy
Modified

Interactive Tables

Interactive tables enable users to actively engage with the data, offering functionalities such as selecting a task or document to edit, or adding a document to their favourites.

Hover effects are always applied to interactive tables, providing a visual cue that the user can select or interact with it.

filter_list cancel
keyboard_arrow_down
Title keyboard_arrow_down
Names
Numbers
Dates
Chips
star Title here SURNAME, Name 12345 dd mmm yyyy
New
error
star Title here SURNAME, Name 12345 dd mmm yyyy
New
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
error
star Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
star Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
star Title here SURNAME, Name 12345 dd mmm yyyy
Overdue
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Modified
star Title here SURNAME, Name 12345 dd mmm yyyy
Overdue

Sorting

Title keyboard_arrow_up
Names
Title here SURNAME, Name
Title here SURNAME, Name
Title here SURNAME, Name

Filtering

Column Filters

- MVP has text-filters. All filter icons in headings can be removed from UI for MVP, but kept aside for post-MVP improvements/ developement
filter_list Title
filter_list Names
Title here SURNAME, Name
Title here SURNAME, Name
Title here SURNAME, Name

Text-Filters

filter_list cancel
Title Names
Title here SURNAME, Name
Title here SURNAME, Name
Title here SURNAME, Name

Pagnation

Reporting Portal Tables

CSS Properties

                
/*TABLES*/
    .table-container {
        width: 100%;
        max-height: 200px; /* Adjust as needed */
        overflow-y: auto;
        margin: 10px;
    }
    table {
        font-family: var(--base-font-family);
        font-size: 14px;
        border: none;
        margin: 0;
        width: 100%;
        border-collapse: collapse;
        table-layout: fixed;
        background-color: white;
    }

    /*Rows*/
        tbody tr:nth-child(odd) {
            background-color: var(--Grey-xxl);
        }
        tbody tr {
            transition: background-color 0s;
        }
        tbody tr:hover { /*this is ONLY for interactive tables*/
            background-color: var(--Grey-xl);
            cursor: pointer; 
        }
        tbody tr.selected {
            background-color: var(--PuertoRico-l);
        }

    /*Cells*/
        th, td {
            padding-left: 10px;
            padding-right: 10px;
            height: 32px;
            text-align: left;
            border-right: 1px solid var(--Grey-l);
            white-space: nowrap; 
            overflow: hidden; 
            text-overflow: ellipsis; 
            font-size: 14px;
        }
        th:last-child,
        td:last-child {
            border-right: none;
        }
        th {
            color: var(--PrussianBlue);
            }

        thead th:hover { /*this is ONLY for interactive headers*/
            background-color: var(--Grey-xl);
            cursor: pointer; 
        }
        td.numbers-column,
        td.date-column {
            text-align: right;
        }
        th.icon-column,
        td.icon-column {
            width: 24px;
        }
        td.icon-column {
            position: relative;
            text-align: center; 
        }
        td.icon-column span {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%); 
        }
        th.chips-column,
        td.chips-column {
            width: 95px;
        }

        /*Sorting*/
            th .sort-icon {
                position: absolute;
                top: 10%;
                right: 45%;
                font-size: 18px;
                display: inline-block;
                transform: translateY(-50%);
                color: var(--Grey-m);
            }

        /*Filters*/
            .filter-icon-wrapper {
                padding: 5px;
                margin-right: 5px;
                display: inline-flex;
                box-sizing: border-box;
                justify-content: center;
                align-items: center;
                border-radius: 5px;
                cursor: pointer;
                background-color: transparent;
            }
            .filter-icon {
                color: var(--Grey-m);
                transition: 0s;
            }
            .filter-icon-wrapper .material-symbols-rounded {
                font-size: 22px;
            }
            .filter-icon-wrapper:hover .filter-icon {
                color: var(--PuertoRico);
            }
            .filter-icon-wrapper:hover {
                background-color: var(--Grey-xxl);
                border-radius: 5px;
            }
            .filter-icon-wrapper.active {
                background-color: var(--PuertoRico);
            }
            .filter-icon-wrapper.active .filter-icon {
                color: white;
            }
            th:has(.filter-icon-wrapper) {
                padding-left: 5px;
                padding-top: 4px;
                padding-bottom: 4px;
            }
            th:has(.filter-icon-wrapper) > div {
                display: flex;
                align-items: center;
            }
        
                /*Text Filters i.e. Table Search box*/
                    .table-filter-container {
                        margin: 10px;
                        max-width: 50%;
                        position: relative;
                    }
                    #tableFilterInput,
                    #tableFilterInput2 {
                        height: 30px;
                        width: 100%;
                        padding: 10px 35px 10px 10px;
                        font-size: 14px;
                        border: 1px solid var(--Grey-l);
                        border-radius: 5px;
                        box-sizing: border-box;
                        font-family: var(--base-font-family);
                        outline: none;
                        transition: 0s;
                    }
                    #tableFilterInput:hover,
                    #tableFilterInput2:hover {
                        border-color: var(--Grey-m);
                    }
                    #tableFilterInput:focus,
                    #tableFilterInput2:focus {
                        border-color: var(--PuertoRico);
                    }
                    .highlight {
                        background-color: #007BFF; /* Standard blue color */
                        color: white;
                        padding: 0 2px;
                    }
                    .filter-icon-visual {
                        position: absolute;
                        right: 10px;
                        margin-left: 8px;
                        top: 40%;
                        scale: 80%;
                        transform: translateY(-50%);
                        color: var(--Grey-l);
                        pointer-events: none; 
                    }
                    #clearFilter,
                    #clearFilter2 {
                        font-size: 20px;
                        margin-left: 8px; 
                        cursor: pointer;
                        color: var(--Grey-m);
                        transition: 0s;
                        position: absolute;
                        right: 10px; 
                        top: 50%;
                        transform: translateY(-50%);
                        z-index: 10;
                        display: none;
                    }
                    #clearFilter:hover,
                    #clearFilter2:hover {
                        color: var(--PuertoRico);
                    }
                    .clear-icon {
                        font-variation-settings:
                        'FILL' 1,
                        'wght' 400,
                        'GRAD' 0,
                        'opsz' 24;
                        color: var(--Grey-m);
                    }
                    #noResultsRow,
                    #noResultsRow2 {
                        background-color: white;
                        pointer-events: none;
                    }
                    #noResultsRow,
                    #noResultsRow2 td {
                        padding: 10px;
                        font-style: italic;
                    }


    /* Fixed Header */
        thead th {
            position: sticky;
            top: 0;
            z-index: 100;
            background-color: white;
        }

    /*Read-only*/
        .read-only-table {
            pointer-events: none;
        } 
        .read-only-table tr:hover {
            background-color: transparent; 
        }

/*Input field*/
    .aios-field-container {
        display: flex;
        margin: 10px;
    }
    .aios-field-label-top { 
        font-size: 14px;
        color: var(--Black);
        font-family: var(--base-font-family);
        margin-bottom: 5px;
    }
    .aios-field-label-left { 
        font-size: 14px;
        color: var(--Black);
        font-family: var(--base-font-family);
        align-self: center;
        width: 100%;
    }
    .aios-field {
        height: 30px;
        font-size: 14px;
        padding-left: 10px;
        color: var(--Black);
        background-color: var(--White);
        border: 1px solid var(--Grey-l);
        border-radius: 5px;
        font-family: var(--base-font-family);
        outline: none;
        transition: 0s;
        width: 100%;
        padding: 10px 35px 10px 10px;
        box-sizing: border-box;
    }
    .aios-field::placeholder {
        color: var(--Grey-ml);
        font-family: var(--base-font-family);
    }
    .aios-field:hover {
        border-color: var(--Grey-md);
    }
    .aios-field:focus {
        border-color: var(--PuertoRico);
    }
    .aios-field:disabled {
        background-color: var(--Grey-xxl);
        border-color: var(--Grey-l);
        cursor: not-allowed;
        color: var(--Grey-l);
    }
    .aios-field:disabled::placeholder {
        color: var(--Grey-d);
    }
    .aios-field:disabled:not([value=""]) {
        color: var(--Grey-d);
    } 

/*Favourites toggle*/

    .favourite-toggle {
        color: var(--Grey-l);
        cursor: pointer;
    }
    .favourite-toggle:hover {
        color: var(--Yellow-ml);
    }
    .favourite-toggle.selected {
        color: var(--Yellow);
    }

                
            

Javascript

                
//JavaScript - Only added in order to make these tables SEMI-functional for presentation purposes

document.addEventListener('DOMContentLoaded', function () {
    var table1 = document.getElementById('SampleTableTextFilter');
    var headers1 = table1.querySelectorAll('th');

    // Check for the default sorted header and apply sorting for SampleTableTextFilter
    headers1.forEach(function (header) {
        var defaultSort = header.getAttribute('data-default-sort');
        if (defaultSort) {
            if (defaultSort === 'asc') {
                header.classList.add('sort-asc');
                header.querySelector('.sort-icon').style.visibility = 'visible';
            } else if (defaultSort === 'desc') {
                header.classList.add('sort-desc');
                header.querySelector('.sort-icon').textContent = 'keyboard_arrow_down';
                header.querySelector('.sort-icon').style.visibility = 'visible';
            }
            // Simulate a click to sort the table based on the default sorted column
            toggleSortDirection(header);
        }
    });

    // Setup for the first table filter
    setupTableFilter('tableFilterInput', 'clearFilter', 'VisualFilterIcon', 'SampleTableTextFilter');

    var table2 = document.getElementById('SampleTableInteractive');
    var headers2 = table2.querySelectorAll('th');

    // Check for the default sorted header and apply sorting for SampleTableInteractive
    headers2.forEach(function (header) {
        var defaultSort = header.getAttribute('data-default-sort');
        if (defaultSort) {
            if (defaultSort === 'asc') {
                header.classList.add('sort-asc');
                header.querySelector('.sort-icon').style.visibility = 'visible';
            } else if (defaultSort === 'desc') {
                header.classList.add('sort-desc');
                header.querySelector('.sort-icon').textContent = 'keyboard_arrow_down';
                header.querySelector('.sort-icon').style.visibility = 'visible';
            }
            // Simulate a click to sort the table based on the default sorted column
            toggleSortDirection(header);
        }
    });

    // Setup for the second table filter
    setupTableFilter('tableFilterInput2', 'clearFilter2', 'VisualFilterIcon2', 'SampleTableInteractive');

    // Add event listener to table rows for selection
    document.querySelectorAll('tbody tr').forEach(row => {
        row.addEventListener('click', function () {
            // Remove selected class from all rows
            document.querySelectorAll('tbody tr.selected').forEach(selectedRow => {
                selectedRow.classList.remove('selected');
            });
            // Add selected class to clicked row
            this.classList.add('selected');
        });
    });
});

function toggleSortDirection(thElement) {
    var table = thElement.closest('table');
    var headers = table.querySelectorAll('th');

    // Remove sort classes and hide icons for all headers except the clicked one
    headers.forEach(th => {
        var icon = th.querySelector('.sort-icon');
        if (th !== thElement) {
            th.classList.remove("sort-asc", "sort-desc");
            if (icon) {
                icon.style.visibility = 'hidden';
            }
        } else {
            icon.style.visibility = 'visible';
        }
    });

    var icon = thElement.querySelector('.sort-icon');
    if (thElement.classList.contains("sort-asc")) {
        thElement.classList.remove("sort-asc");
        thElement.classList.add("sort-desc");
        icon.textContent = 'keyboard_arrow_down';
    } else {
        thElement.classList.remove("sort-desc");
        thElement.classList.add("sort-asc");
        icon.textContent = 'keyboard_arrow_up';
    }
}

function toggleFilter(element) {
    element.classList.toggle('active');
}

function setupTableFilter(inputId, clearIconId, filterIconId, tableId) {
    const filterInput = document.getElementById(inputId);
    const clearFilterIcon = document.getElementById(clearIconId);
    const visualFilterIcon = document.getElementById(filterIconId);

    // Function to handle filter input
    filterInput.addEventListener('input', function () {
        const filter = this.value.toLowerCase();
        const table = document.getElementById(tableId);
        const tbody = table.getElementsByTagName('tbody')[0];
        const rows = tbody.getElementsByTagName('tr');

        // Show/hide clear icon and filter icon based on input presence
        if (filter) {
            clearFilterIcon.style.display = 'inline';
            visualFilterIcon.style.display = 'none';
        } else {
            clearFilterIcon.style.display = 'none';
            visualFilterIcon.style.display = 'inline';
        }

        let resultsFound = false;
        Array.from(rows).forEach(row => {
            const cells = row.getElementsByTagName('td');
            let matchFound = false;

            Array.from(cells).forEach(cell => {
                const originalText = cell.getAttribute('data-original-text') || cell.textContent;
                const lowerCaseText = originalText.toLowerCase();

                // Store the original text if not already stored
                if (!cell.getAttribute('data-original-text')) {
                    cell.setAttribute('data-original-text', originalText);
                }

                // Highlight matching text
                if (lowerCaseText.includes(filter)) {
                    matchFound = true;
                    const startIndex = lowerCaseText.indexOf(filter);
                    const endIndex = startIndex + filter.length;
                    const highlightedText = originalText.substring(startIndex, endIndex);
                    const highlightedHtml = originalText.substring(0, startIndex) +
                        'span class="highlight">' + highlightedText + '/span>' +
                        originalText.substring(endIndex);
                    cell.innerHTML = highlightedHtml;
                } else {
                    cell.innerHTML = originalText;
                }
            });

            // Show/hide rows based on filter match
            if (matchFound) {
                row.style.display = '';
                resultsFound = true;
            } else {
                row.style.display = 'none';
            }
        });

        // Show no results row if no matches found
        if (!resultsFound) {
            if (tableId === 'SampleTableInteractive') {
                noResultsRow.style.display = '';
            } else if (tableId === 'SampleTableTextFilter') {
                noResultsRow2.style.display = '';
                document.getElementById('searchTerm2').textContent = filter;
            }
        } else {
            if (tableId === 'SampleTableInteractive') {
                noResultsRow.style.display = 'none';
            } else if (tableId === 'SampleTableTextFilter') {
                noResultsRow2.style.display = 'none';
            }
        }
    });

    // Function to clear filter
    clearFilterIcon.addEventListener('click', function () {
        filterInput.value = ''; // Clear filter input
        clearFilterIcon.style.display = 'none'; // Hide clear icon
        visualFilterIcon.style.display = 'inline'; // Show filter icon

        const table = document.getElementById(tableId);
        const tbody = table.getElementsByTagName('tbody')[0];
        const rows = tbody.getElementsByTagName('tr');

        // Clear filter highlighting
        Array.from(rows).forEach(row => {
            const cells = row.getElementsByTagName('td');
            Array.from(cells).forEach(cell => {
                const originalText = cell.getAttribute('data-original-text');
                if (originalText !== null) {
                    cell.innerHTML = originalText;
                } else {
                    cell.innerHTML = cell.textContent; // Ensure no highlight remnants
                }
            });
            row.style.display = ''; // Show all rows
        });

        // Hide no results row when filter is cleared
        if (tableId === 'SampleTableInteractive') {
            noResultsRow.style.display = 'none';
        } else if (tableId === 'SampleTableTextFilter') {
            noResultsRow2.style.display = 'none';
        }
    });

    //Favourites Toggle
    document.querySelectorAll('.favourite-toggle').forEach(star => {
        star.addEventListener('click', function(event) {
            event.stopPropagation(); // Prevents the row from being selected
            this.classList.toggle('selected'); // Toggle the 'selected' class
        });
    });   
}