<table border="1">
This is a quick way to add a visible outline. You can even make them thicker, like:
<table border="5">
The above will render thick borders, like this:

But there is a catch…
Why use it? border Not a best practice
border Attribute is an old, inline styling technique. Modern web development separates structure (HTML) from presentation (CSS). This means we now use CSS for all visual styling.
Here is the modern equivalent:
table {
border-collapse: collapse;
border: 2px solid #444;
}
th, td {
border: 1px solid #666;
padding: 8px;
text-align: left;
}
When to use HTML vs JavaScript for tables
You can create tables entirely in HTML, but only if the data is static.
use HTML Only when:
Data doesn’t change often (like a static price list).
You know the correct number of rows and columns.
You are not taking data from an external source.
use JavaScript when:
The data is dynamic (for example, retrieved from an API).
You want to update a table based on user input.
You may want to interactively sort, filter, or paginate your table.
JavaScript allows you to create programs programmatically by specifying data in an array or object and letting code handle the rendering.
How to dynamically create a table with javascript
Now we will create a dynamic table using JavaScript. First, I’ll show you the complete code, and then we’ll break it down step by step so you can understand what’s going on.
Code example:
html>
<html>
<head>
<title>JS Table Exampletitle>
head>
<body>
<div id="table-container">div>
<script>
const data = (
{ name: "Fahim", age: 25, job: "Software Engineer" },
{ name: "Sara", age: 29, job: "Designer" },
{ name: "David", age: 31, job: "Manager" }
);
const table = document.createElement("table");
table.border = "1";
const headers = ("Name", "Age", "Job");
const headerRow = document.createElement("tr");
headers.forEach(text => {
const th = document.createElement("th");
th.textContent = text;
headerRow.appendChild(th);
});
table.appendChild(headerRow);
data.forEach(item => {
const row = document.createElement("tr");
Object.values(item).forEach(value => {
const cell = document.createElement("td");
cell.textContent = value;
row.appendChild(cell);
});
table.appendChild(row);
});
document.getElementById("table-container").appendChild(table);
script>
body>
html>

Step by step explanation
Step 1: Define the data – separating the data from the presentation
In web development, data and presentation should be kept separate. In this context, data is the content (such as name, age, jobs) and presentation is how the data looks (HTML table layout, colors and so on).
We define our data as an array of objects:
const data = (
{ name: "Fahim", age: 25, job: "Software Engineer" },
{ name: "Sara", age: 29, job: "Designer" },
{ name: "David", age: 31, job: "Manager" }
);
This structure keeps our data flexible. If you later fetch it from an API or database, your table rendering logic remains the same.
This also mirrors how modern frameworks (like React or Woo) work: your UI is simply what your data is.
Step 2: Create the table element
const table = document.createElement("table");
table.border = "1";
Here we are using document.createElement()a DOM API method that programmatically creates elements. We haven’t added it to the page yet. It is only stored in memory.
So why build it into memory in the first place? Well, that’s fast. Adding too many elements to the DOM causes one-one-one reflows (the browser’s fetching configuration). Building the structure first and adding it once at the end reduces configuration maintenance and improves performance.
const headers = ("Name", "Age", "Job");
const headerRow = document.createElement("tr");
headers.forEach(text => {
const th = document.createElement("th");
th.textContent = text;
headerRow.appendChild(th);
});
table.appendChild(headerRow);
Here, we loop and dynamically create the header labels
We generate headers automatically because if you later load data from a JSON file, you can automatically extract column names using Object.keys(data(0)). This avoids hardcoding and makes your table generation more flexible.
Step 4: Populate the data rows
data.forEach(item => {
const row = document.createElement("tr");
Object.values(item).forEach(value => {
const cell = document.createElement("td");
cell.textContent = value;
row.appendChild(cell);
});
table.appendChild(row);
});
We loop through each data object, creating a
cells for each value. textContent Ensures we insert text safely (no HTML injection).Step 5: Insert the table into the DOM
document.getElementById("table-container").appendChild(table);
This is where our table finally appears on the page. We select blank
(our placeholder) and append the built table to it.JavaScript does not automatically add tables. It only creates them because we told it to. The appendChild() The call is what actually adds it directly to the DOM.
Why is this approach better?
Using JavaScript to create tables has several advantages:
Reuse: You can reuse the same code for any dataset - just change the array.
Separation of Concerns: Data (JS), structure (HTML), and design (CSS) are all handled independently.
Performance: Creating tables in memory first avoids expensive DOM reflows.
Interaction: You can easily add features like sorting, filtering, or row highlighting.
Dynamic Data: This is the natural approach when fetching JSON data from APIs.
How to Add CSS Classes for Styling
Instead of inline styling, we'll use classes for better organization:
table.classList.add("data-table");
Then we define our style in CSS:
.data-table {
border-collapse: collapse;
border: 2px solid #333;
width: 100%;
}
.data-table th, .data-table td {
border: 1px solid #888;
padding: 10px;
}
When we say "use them", we're referring to the CSS class names.
How to turn it into a reusable function
Finally, let's make this process reusable. We can wrap everything in a function that produces any table given some data and headers.
function createTable(data, headers, containerId) {
const table = document.createElement("table");
const headerRow = document.createElement("tr");
headers.forEach(text => {
const th = document.createElement("th");
th.textContent = text;
headerRow.appendChild(th);
});
table.appendChild(headerRow);
data.forEach(item => {
const row = document.createElement("tr");
Object.values(item).forEach(value => {
const td = document.createElement("td");
td.textContent = value;
row.appendChild(td);
});
table.appendChild(row);
});
document.getElementById(containerId).appendChild(table);
}
Then use it like this:
createTable(data, ("Name", "Age", "Job"), "table-container");
When and why to use a function
This pattern is ideal when you need to generate multiple tables on a page, you want clean, modular, and testable code, or you plan to integrate with dynamic data sources (such as APIs).
Final thoughts and conclusion
We've covered a lot! In this article, let's recap what we've learned:
How to create a table with HTML
How to style it properly using CSS
When to use HTML vs JavaScript
How to separate data from presentation
How to Create Dynamic Tables with JavaScript
How to make your code repeatable and efficient
With these foundations in place, you can now create tables that are dynamicfor , for , for , . Styledfor , for , for , . And data-driven - using nothing but vanilla JavaScript.
Thank you for reading the entire article. I hope you've gained some insight into how to properly transition from plain HTML tables to dynamic JavaScript-based tables. To get more content like this, you can follow me LinkedIn And x. You can also check My website And follow me GitHub If you are into open source and development.
If you read this far, thank the author for caring.
Learn to code for free. Free CodeCamp's open-source curriculum has helped more than 40,000 people land jobs as developers. Start