Add CSS style and media queries to dynamically generated HTML table with JavaScript

Viewed 695

I have an HTML table that's been created and populated dynamically with JavaScript.

I want to dynamically apply the CSS style and media queries to the HTML table.

Approaches I've tried.

  1. I defined the style in a separate file and reference it in the HTML file
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link href="style.css" rel="stylesheet" />
        <title>Document</title>
      </head>
      <body>
        <table id="data-tb"></table>
        <script>
            // JavaScript code goes here...
        </script>
      </body>
    </html>

The CSS style and that of media queries do not work. The styles didn't apply to the HTML table that was dynamically generated.

  1. I defined the style inside the HTML file within the script tag.
 <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link href="style.css" rel="stylesheet" />
        <title>Document</title>
      </head>
      <body>
        <table id="data-tb"></table>
        <script>
                document.head.innerHTML += `
      <style>
        body {
      font-family: "Open Sans", sans-serif;
      line-height: 1.25;
    }
    
    table {
      border: 1px solid #ccc;
      border-collapse: collapse;
      margin: 0;
      padding: 0;
      width: 100%;
      table-layout: fixed;
    }
    
    table caption {
      font-size: 1.5em;
      margin: 0.5em 0 0.75em;
    }
    
    table tr {
      background-color: #f8f8f8;
      border: 1px solid #ddd;
      padding: 0.35em;
    }
    
    table th,
    table td {
      padding: 0.625em;
      text-align: center;
    }
    
    table th {
      font-size: 0.85em;
      letter-spacing: 0.1em;
      text-transform: uppercase;
    }
    
    @media screen and (max-width: 600px) {
      table {
        border: 0;
      }
    
      table caption {
        font-size: 1.3em;
      }
    
      table thead {
        border: none;
        clip: rect(0 0 0 0);
        height: 1px;
        margin: -1px;
        overflow: hidden;
        padding: 0;
        position: absolute;
        width: 1px;
      }
    
      table tr {
        border-bottom: 3px solid #ddd;
        display: block;
        margin-bottom: 0.625em;
      }
    
      table td {
        border-bottom: 1px solid #ddd;
        display: block;
        font-size: 0.8em;
        text-align: right;
      }
    
      table td::before {
        content: attr(data-label);
        float: left;
        font-weight: bold;
        text-transform: uppercase;
      }
    
      table td:last-child {
        border-bottom: 0;
      }
    }
    
    
      </style>`;
    
            // JavaScript code goes here...
        </script>
      </body>
    </html>

In the second approach, the CSS style work. But the media queries for screen (max-width: 600px) do not work.

How can I dynamically apply the CSS style and media queries to the HTML table created and populated with JavaScript?

3 Answers

you can use window.matchMedia for check media query in js and then add styles like that:

let myMediaQuery = window.matchMedia('(min-width: 768px)')

if (myMediaQuery.matches) {
  el.styles.background= "blue"
}

What AhmadKZX will work but I would prefer to set the styles in CSS and then while adding the elements with javascript, set the attributes of the elements to the style you want. The code can be refactored to match whatever you want.

const tr = document.createElement('tr');
const column1 = document.createElement('td');
const column2 = document.createElement('td');
const column3 = document.createElement('td');
const column4 = document.createElement('td');

column1.innerHTML = "03/44/33";
column2.innerHTML = "Visa 001";
column3.innerHTML = "#1,300,331";
column4.innerHTML = "1/22/33 - 12/55/33";
column1.setAttribute("data-label", "Date");
column2.setAttribute("data-label", "Account");
column3.setAttribute("data-label", "Amount");
column4.setAttribute("data-label", "Period");
tr.appendChild(column1);
tr.appendChild(column2);
tr.appendChild(column3);
tr.appendChild(column4);
document.querySelector('tbody').appendChild(tr);
table {
  border: 1px solid #ccc;
  border-collapse: collapse;
  width: 100%;
}

table caption {
  font-size: 34px;
  margin: 8pxx 0 12px;
}

table tr {
  background-color: #f8f8f8;
  border: 1px solid #ddd;
  padding: 5px;
}

table th,
table td {
  padding: 12px;
  text-align: center;
}

table th {
  font-size: 13px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}

@media screen and (max-width: 600px) {

  table caption {
    font-size: 24px;
  }
  
  table thead {
    border: none;
    width: 1px;
  }
  
  table tr {
    border-bottom: 3px solid #ddd;
    display: block;
    margin-bottom: .13px;
  }
  
  table td {
    border-bottom: 1px solid #ddd;
    display: block;
    font-size: 12px;
    text-align: right;
  }
  
  table td::before {
    content: attr(data-label);
    float: left;
    font-weight: bold;
    text-transform: uppercase;
  }
  

}
<table>
  <caption>Statement Summary</caption>
  <thead>
    <tr>
      <th scope="col">Account</th>
      <th scope="col">Due Date</th>
      <th scope="col">Amount</th>
      <th scope="col">Period</th>
    </tr>
  </thead>
  <tbody>
   
  </tbody>
</table>

I was trying to create a simple responsive table in CSS. The example code I found required the header labels to be hardcoded on the <td></td> tags. But I wanted a way to dynamically label the <td></td> tags with the table headers content when the window resizes.

Since I am new to CSS and JS, I had no idea of accessing the content attribute of an HTML element. @Immaculata's answer gave me a hint.

See working code below.

CSS: defined within the @media screen and (max-width: 600px)

table td::before {
    content: attr(data-label);
    float: left;
    font-weight: bold;
    text-transform: uppercase;
  }

HTML and JavaScript

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://unpkg.com/read-excel-file@4.x/bundle/read-excel-file.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <title>Document</title>
  </head>
  <body>
    <input type="file" id="input" />
    <table>
      <caption>
        Table Title
      </caption>
    </table>
    <script>

      var input = document.getElementById("input");
      input.addEventListener("change", function () { 

        //Code to populate the HTML table goes here...

    });

      const mediaQuery = window.matchMedia("(max-width: 600px)");
      mediaQuery.addListener(onWindowChanged);

      function onWindowChanged(e) {
        if (e.matches) {
          const dataTable = document.querySelector("table");
        const thElements = dataTable.querySelectorAll("thead th");
        const tdLabels = Array.from(thElements).map((element) => element.innerText);
        dataTable.querySelectorAll("tbody tr").forEach((tr) => {
          Array.from(tr.children).forEach((td, index) =>
            td.setAttribute("data-label", tdLabels[index])
          );
        });
        }
      }
     
    </script>
  </body>
</html>
Related