Exploring ways to repeatedly collapse rows using HTML, CSS, and JavaScript

GOAL: I want to freeze the header, freeze the first column, and be able to collapse rows multiple times.

CURRENT PROGRESS: I have achieved freezing the header, first column, but can only collapse rows once.

MY CODE SNIPPET:

</head>
<body>
<div class="table-container">
<table>
<thead class="freeze-header">
<tr>
<th class="freeze-col">Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr class="parent-row">
<td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 1, Column 1</td>
<td>Row 1, Column 2</td>
</tr>
<tr class="collapse">
<td colspan="3">
<table>
<tbody>
<tr class="parent-row">
<td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 1.1, Column 1</td>
<td>Row 1.1, Column 2</td>
</tr>
<tr class="collapse">
<td colspan="3">
<table><tbody><tr>
<td>Row 1.1.1, Column 1</td>
<td>Row 1.1.1, Column 2</td>
</tr></tbody></table></td></tr></tbody></table></td></tr>
<tr class="parent-row">
<td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 2, Column 1</td>
<td>Row 2, Column 2</td>
<td>Row 2, Column 3</td>
</tr>
</tbody></table></div>

<script>
    // JavaScript for collapsing rows
    document.querySelectorAll('.parent-row').forEach(function(row) {
        row.addEventListener('click', function() {
            var nextRow = row.nextElementSibling;
            if (nextRow && nextRow.classList.contains('collapse')) {
                nextRow.classList.toggle('show');
                row.querySelector('.collapse-icon').classList.toggle('fa-caret-right');
                row.querySelector('.collapse-icon').classList.toggle('fa-caret-down');
            }
        });
    });
</script>

Answer №1

If you want to implement a frozen header, a frozen first column, and collapsible rows in your table, you just need to make a few tweaks to your current code. Here's an enhanced version that incorporates these functionalities:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
    <style>
        .table-container {
            overflow-x: auto;
            max-width: 100%;
            position: relative;
        }

        table {
            border-collapse: collapse;
            width: 100%;
        }

        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }

        th.freeze-col, td.freeze-col {
            position: sticky;
            left: 0;
            background-color: #f2f2f2;
        }

        .freeze-header th {
            position: sticky;
            top: 0;
            background-color: #f2f2f2;
        }

        .collapse {
            display: none;
        }

        .collapse.show {
            display: table-row;
        }

        .collapse td {
            padding-left: 30px;
        }

        .collapse .freeze-col {
            position: static;
            background-color: #fff;
        }

        .collapse-icon {
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="table-container">
        <table>
            <thead class="freeze-header">
                <tr>
                    <th class="freeze-col">Header 1</th>
                    <th>Header 2</th>
                    <th>Header 3</th>
                </tr>
            </thead>
            <tbody>
                <tr class="parent-row">
                    <td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 1, Column 1</td>
                    <td>Row 1, Column 2</td>
                    <td>Row 1, Column 3</td>
                </tr>
                <tr class="collapse">
                    <td colspan="3">
                        <table>
                            <tbody>
                                <tr class="parent-row">
                                    <td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 1.1, Column 1</td>
                                    <td>Row 1.1, Column 2</td>
                                    <td>Row 1.1, Column 3</td>
                                </tr>
                                <tr class="collapse">
                                    <td colspan="3">
                                        <table>
                                            <tbody>
                                                <tr>
                                                    <td>Row 1.1.1, Column 1</td>
                                                    <td>Row 1.1.1, Column 2</td>
                                                    <td>Row 1.1.1, Column 3</td>
                                                </tr>
                                            </tbody>
                                        </table>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </td>
                </tr>
                <tr class="parent-row">
                    <td class="freeze-col"><i class="fas fa-caret-right collapse-icon"></i> Row 2, Column 1</td>
                    <td>Row 2, Column 2</td>
                    <td>Row 2, Column 3</td>
                </tr>
            </tbody>
        </table>
    </div>

    <script>
        document.querySelectorAll('.parent-row').forEach(function(row) {
            row.addEventListener('click', function() {
                var nextRow = row.nextElementSibling;
                if (nextRow && nextRow.classList.contains('collapse')) {
                    nextRow.classList.toggle('show');
                    row.querySelector('.collapse-icon').classList.toggle('fa-caret-right');
                    row.querySelector('.collapse-icon').classList.toggle('fa-caret-down');
                }
            });
        });
    </script>
</body>
</html>

This updated code now includes CSS styles for freezing the header and first column, as well as managing collapsible rows. The JavaScript function for handling collapsed rows remains unchanged. Feel free to further customize the styles to suit your design needs.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for displaying a placeholder image within the Next.js image component

I am currently facing an issue with displaying images from API calls. To handle situations where there are no images or errors, I have implemented a code snippet which includes a placeholder image. However, the implementation seems to not be functioning as ...

Certain javascript files have had illegal characters mistakenly added to them

There seems to be an issue with the js files or server on certain pages, as they are not loading in Firefox: with firefox: SyntaxError: illegal character 癡爠浥湵楤猠㵛≶敲瑩捡汭敮產崻 ⽅湴敲⁩搨猩映啌敮畳Ⱐ獥灡牡瑥 ...

Is there a conflict between bootstrap.min.JS and chart.min.js?

I have been working on developing an admin page for customer support and I recently added a visually appealing chart to display some data on the home screen. The chart integration was successful, but when I introduced tab panes to the page and refreshed ...

Experiencing challenges accessing information from the useEffect hook in React

I'm facing some issues with my useEffect hook and I can't seem to figure out why it's not working. I've been trying to make a call to an endpoint, but it seems like I'm not getting any response back. Any help would be greatly appr ...

Issues arising from utilizing Twitter Bootstrap 3.1.x, the box-sizing property, and Revolution Slider

I'm currently working on a PyroCMS theme that is built with Twitter Bootstrap 3.1.x and includes Revolution Slider. However, I've encountered an issue where the property box-sizing: border-box; creates an unwanted grey border as shown in the imag ...

Leverage the power of Vue Nuxt Auth to activate authentication middleware on a route-by-route

Is there a way to implement auth middleware for individual routes using Class Components? How can I achieve the same functionality as this: <script> export default { middleware: 'auth' } </script> The following method does n ...

What is the reasoning behind an empty input value being considered as true?

I am facing an issue with the following code that is supposed to execute oninput if the input matches the answer. However, when dealing with a multiplication problem that equals 0, deleting the answer from the previous calculation (leaving the input empt ...

Tips for implementing a dynamic value in the ng-style based on certain conditions

Is there a way to set a background-color conditionally using ng-style when the color value can be updated from $scope? These are the variables in my scope: $scope.someone = { id: '1', name: 'John', color: '#42a1cd' }; $scope ...

The functionality of the AJAX Script is failing to load properly on mobile devices

Currently, I am undertaking a project that involves ESP32 Arduino programming to create a webpage where users can interact with buttons to activate relays. Additionally, I have implemented a slider using a short script. This project is inspired by the ESP3 ...

Execute a single test from a particular test suite using Jest

Within my file named "test-file-1", I have several describes (test suites) with distinct names, each containing tests that may share similar names across different test suites. In order to run a single test suite or test, I enter the following command: n ...

Unusual class exhibiting peculiar async/await patterns

Node 7.9.0 The situation goes like this: class TestClass { constructor() { const x = await this.asyncFunc() console.log(x) } async asyncFunc() { return new Promise((accept) => { setTimeout(() => accept("done"), 1000) }) ...

Loading textures locally using three.js is functioning properly, however, remote loading is not functioning as

I have customized an official example for the Loader object to showcase a specific issue. My goal is to generate a mesh with a texture map that loads before creating the geometry. Currently, I am facing a problem where local files load properly, but remote ...

What is the best way to center my text vertically within a Bootstrap 5 "col" class division?

Struggling to create a Bootstrap 5 page and facing challenges with vertically aligning text in divs? Here's the code snippet causing problems: <link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

Issue: tanstack_react_query's useQuery function is not recognized

Error: (0 , tanstack_react_query__WEBPACK_IMPORTED_MODULE_3_.useQuery) is not a function While implementing data fetching in my Next.js project using @tanstack/react-query, I encountered the above error message. Below is the code snippet where the issue ...

Deploy a Node.js websocket application on Azure Cloud platform

After smoothly running on Heroku, the server app encountered a problem with startup after moving to Azure. Below is the code snippet: const PORT = process.env.PORT || 2498; const INDEX = '/index.html'; const server = express() .use((req, res ...

Tips on using Jquery to animate an element to a specific pixel measurement

My expertise lies in executing the following code: $("#nurseView").animate({"left": "+=100px"}, "slow"); However, I am facing a dilemma. How can I animate an object to exactly 1576px on the X-axis regardless of its current position? The code snippet abov ...

Discovering and updating a DOM element with a rejuvenating touch: Angular JS

Although not very experienced with Angular JS, here's what I currently have and what I aim to achieve: <div ng-app="MyApp" ng-controller="appController"> <div class="input-group"> <input class="form-control enableEnter" type=" ...

Make sure to save the data in a file correctly by utilizing JSON.stringify before storing

When I use this code snippet: function item(name, number){ this.name = name; this.number = number; } var item1 = new item('a',1); var item2 = new item('b',2); var box1 = [item1,item2]; console.log(box1); var box2 = JSON.strin ...

Tips for choosing a single checkbox from a set of multiple checkboxes in React.js

I iterated through a list of objects to generate table rows, each containing an input tag with the type set as checkbox. const [ isChecked, setIsChecked ] = useState(false); const handleChange = (e) => { setIsChecked(e.target.checked) ...

calculation of progress bar advancement

I want to make the progress bar in my game responsive to changes in the winning score. Currently, it moves from 0% to 100%, which is equivalent to 100 points - the default winning score. But I need the progress bar to adjust accordingly based on the user-i ...