Today I got a very exciting project for you to learn about web development and building Interactive UI with HTML CSS JavaScript, We are going to build an Interactive dynamic Table with HTML CSS JavaScript, We are going to be able to Create and Delete Rows and Columns Alos we going to be able to edit the cells, All this will be wrapped around a simple and easy to use UI.
What is a table
A table is an arrangement of information or data, typically in rows and columns, or possibly in a more complex structure. Tables are widely used in communication, research, and data analysis.
Wikipedia
What we are going to learn
We are going to learn How to interact With the DOM (Document Object Module) create and delete Elements using JavaScrip, And most important we are going to learn How to build useful tools with the skills we have.
Let's Start Building an interactive Table editor
We are going to use HTML/CSS and JavaScript to build this Dynamic Table editor,
You will find the source code on my Github repository here, feel free to use edit, or sell it.
.Step 1 Project Setup
First will setup the project folder and file structure it's going to be fairly simple since the project is not that big.
Create a folder at your computre and it's going to have 3 main files index.html style.css app.js as shown down here in the shnapshoot
.Step 2 HTML Mockup
The HTML mockup consists of a page title and table also there are a few buttons that will allow us to control the table later when we add JavaScript Code
For Icons I'm using the Boxicons library it has great looking Icon free to use and its easy to implement in your projects, also it has Good documentation
<!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" />
<title>Table editor</title>
<link
href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="style.css" />
<script defer src="/app.js"></script>
</head>
<body>
<h1 class="title">Interactive table editor</h1>
<div class="container">
<div class="table-wrapper">
<!-- when this button is clicked it will add a column to the table -->
<button class="circle-button add-column" title="Add Column">
+
</button>
<!-- And this button will add a row to the table -->
<button class="circle-button add-row" title="Add Row">+</button>
<!-- This button will appear next to a row when it's focused -->
<!-- When it's clicked it will delete the entire row -->
<button
id="delete-row"
class="delete-btn point-right"
title="Delete this row"
>
<i class="bx bx-trash"></i>
</button>
<!-- This button will appear on top of each column when it's focused -->
<!-- Also when it's clicked will delete the row below it -->
<button
id="delete-column"
class="delete-btn point-bottom"
title="Delete this Column"
>
<i class="bx bx-trash"></i>
</button>
<!-- This is the main table will use it as a demo -->
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Position</th>
<th>Location</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Bob Dylan</td>
<td>Musician</td>
<td>California, USA</td>
</tr>
<tr>
<td>2</td>
<td>Eric Clapton</td>
<td>Musician</td>
<td>Ohio, USA</td>
</tr>
<tr>
<td>3</td>
<td>Daniel Kahneman</td>
<td>Psychologist</td>
<td>California, USA</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
Copy.Step 3 CSS styling
Adding CSS styles will be very easy at top of the style.css file will add some global styles and rests so the UI will be consistent in all the browsers, as you can see we are using CSS variables if you are not familiar with it just check this blog post by freecodecamp it will help you learn more about them
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--accent: #1977e2;
}
html {
font-size: 15px;
}
body {
font-size: 1rem;
line-height: 1.5;
font-weight: 400;
background-color: white;
letter-spacing: 0.02em;
font-family: Inter, sans-serif;
}
CopyNext we will add styles on the page title and linear gradient as text color it will look cool as show here
If you like to go indepth in css I highly recomend the blog by Manuel Matuzović you will learn a lot for it
.title {
text-align: center;
margin-top: 3rem;
margin-bottom: 5rem;
font-size: 40px;
text-transform: capitalize;
background: linear-gradient(45deg, var(--accent), #1bffff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
CopyAnd this is hwo it looks like very cool right
After that will add styles to thebuttons and as well as the container of the page and table wrapper
/* Page container */
.container {
padding: 0 2rem;
max-width: 1100px;
margin: 0 auto;
}
/* Buttons styles */
button {
border: 0;
outline: 0;
cursor: pointer;
line-height: 1;
}
button:hover {
opacity: 0.9;
}
.delete-btn {
display: none;
position: absolute;
background-color: #ffd8d8;
font-size: 17px;
width: 26px;
height: 26px;
color: #e61919;
border-radius: 4px;
left: -31px;
top: 0;
}
.delete-btn.active {
display: initial;
}
.delete-btn.point-right::after,
.delete-btn.point-bottom::after {
content: "";
display: inline-block;
position: absolute;
border: 4px solid transparent;
}
.delete-btn.point-right::after {
right: -8px;
top: 9px;
border-left-color: #ffd8d8;
}
.delete-btn.point-bottom::after {
bottom: -8px;
left: 9px;
border-top-color: #ffd8d8;
}
.circle-button {
background-color: var(--accent);
color: white;
width: 24px;
height: 24px;
font-size: 18px;
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
.table-wrapper {
position: relative;
max-width: 100%;
}
.add-column {
position: absolute;
right: -24px;
top: calc(20px - 12px);
border-radius: 0 50% 50% 0;
}
.add-row {
position: absolute;
bottom: -24px;
left: calc(50% - 12px);
border-radius: 0 0 50% 50%;
}
CopyNow onlay the table is left wethout styling it going to be very easy
The border-collapse property sets whether table borders should collapse into a single border or be separated as in standard HTML.
w3schools
.table {
width: 100%;
/* This one the most important property when it comes */
/* to Adding borders to the table */
border-collapse: collapse;
text-align: center;
vertical-align: middle;
}
.table th,
.table td {
border: 1px solid #ddd;
padding: 8px 14px;
}
/* When the cell is focused will add an outline to highlighted */
.table th:focus,
.table td:focus {
outline: 1.5px solid #6998ce;
outline-offset: -1px;
}
CopyStep 4 and Most important Adding javaScript functionality
First will create a simple function that will help us select elements from the DOM easily, basically, we are just going to wrap it around the document.querySelector
and document.querySelectorAll
based on the given parameter if we call it like this $("div")
it going to return a single div element from the DOM, If we call with parameters like this $("ul li", true)
it will return an array of elements based on the given selector
If you are not familiar with the querySelector
method just check out this article by MDN It will help learn more about its very important method when it comes to interacting with DOM
function $(selector, selectAll = false) {
if (selectAll) {
return document.querySelectorAll(selector);
}
return document.querySelector(selector);
};
CopyHave you ever wandered how you can add you own custom method on all HTML Elements will today we are going to learn how
If you want to add custom method that you can You just have to add your method to the HTMLElement class
We are going to access the HTMLElement prototype and will add a new method will call it on
basically on
method will simplify how we add events
HTMLElement.prototype.on = function (event, callback) {
this.addEventListener(event, callback);
};
CopyNow let's see how we can use these helper functions and methods, Let's say we want to select a button from the DOM that has a class of btn and we want to add a click event when that button is clicked we will log to the console hello word message
// Select the button from the DOM
let btn = $('.btn');
// Add click event on the button
btn.on('click', (event) => {
console.log("Hello world!")
});
CopyNow that out of the way let strat working building the Dynamic interactive table editor
Will add these variables on the top of the app.js file so that when we focus on a row or column we will assign it to the proper variable, by default it is set to null
And they should be declared by using the let
keyword, not const
because any variable declared by let
you can overwrite its value but you can't with const
you can learn more about the difference between let
and const
here
let selectedRow = null;
let selectedColumn = null;
CopyAfter that we need to grab all the buttons and Elements we need from the DOM
First will get all cells in the page which means all <th>
and <td>
tags inside of the table
const cells = $(".table th, .table td", true);
CopySecond will grab all the buttons
const addColumnBtn = $(".add-column");
const addRowBtn = $(".add-row");
const deleteRowBtn = $("#delete-row");
const deleteColumnBtn = $("#delete-column");
CopyNow we are going to make all cells in the table editable by setting the contentEditable
attribute to "true"
if the contnetEdibale
attribute is set to "true"
it allows us to edit the text inside element
And register events on the cells based on its tag
cells.forEach((cell) => {
// make the cells editable
cell.contentEditable = "true";
registerCellEvents(cell, cell.tagName.toLowerCase());
});
CopyAnd this is what the registerCellEvents
the function does, it adds the focus event on the cell and calls the handleCellFocus
function if the tag is td
if the tag is th
It will call the handleCellHeadFocus
function
function registerCellEvents(cell, cellType) {
if (cellType === "td") {
cell.on("focus", handleCellFocus);
}
if (cellType === "th") {
cell.on("focus", handleCellHeadFocus);
}
}
CopyNow let see what these function does
The handleCellFocus function when it is called will get the row of the table which is the parent Element of the td
we will call it row as shown down here, New will set the selectedRow
variable to the currently focused row, then will make the delete row button active by adding the active class it will make it visible, and then we set its position relative to the selected row by getting the offsetTop property on the row
function handleCellFocus(e) {
let row = e.target.parentElement;
selectedRow = row;
deleteRowBtn.classList.add("active");
deleteRowBtn.style.top = row.offsetTop + 6 + "px";
}
CopyNow will put the delete column button on top of the focused head cell, When the cells are focused will call the function handleCellHeadFocus
this function will set selectedColumn
to the currently focused cell in the head of the table and then it will active the delete column button, Next It will get the left and the top position values from the cell in order to put the button on top of the selected column
function handleCellHeadFocus(e) {
let column = e.currentTarget;
selectedColumn = column;
deleteColumnBtn.classList.add("active");
let y = column.offsetTop - deleteColumnBtn.clientHeight - 6 + "px";
let x =
column.offsetLeft +
column.clientWidth / 2 -
deleteColumnBtn.clientWidth / 2 +
"px";
deleteColumnBtn.style.top = y;
deleteColumnBtn.style.left = x;
}
CopyAnd this leads us to the next task, When the the delete buttons are clicked will handle theme
Will start with the delete row button, First will register the click event when its clicked will call the deleteRow
function to handle the deletion or the currently selected row, which what assigned to the selectedRow
variable before when the row was focused
deleteRowBtn.on("click", deleteRow);
CopyNow let us see the deleteRow
function what it does when it's called
So basically, it checks if there is a selected row, and if there is it will remove it from the DOM by calling the remove() method on the selectedRow
element and then it will remove the active class from the delete row button so it won't be visible
function deleteRow(e) {
if (selectedRow) {
selectedRow.remove();
deleteRowBtn.classList.remove("active");
}
}
CopyNow that's Done let see how can we delete a coulmn from the dynamic table editor
It checks if there is a selected column, and then it removes the active class from the delete column button, After that get the cell index It will help us determine what cells in the dynamic table rows should be deleted in order to delete the entire column, then It removes the cell in the head which is called the selectedColumn
after that, it loops over all the rows in the dynamic table and for each row, it gets its children and then deletes the child with the same index as the cell in the head
function deleteColumn(e) {
if (!selectedColumn) return;
deleteColumnBtn.classList.remove("active");
let cellIndex = selectedColumn.cellIndex;
selectedColumn.remove();
$(".table tbody tr", true).forEach((row) => {
row.children[cellIndex].remove();
});
}
CopyNow will handle adding rows and columns as you can see hear
Before we start adding rows and columns we need a function that will help us create new cells
The createCell
function takes a parameter which is the type of the cell and the type either it's going to be td
or th
then we make it editable by setting the attribute contentEditable
to true
after that will register the cell events as I explained before and return the cell Element
function createCell(type) {
let cell_el = document.createElement(type);
cell_el.contentEditable = "true";
registerCellEvents(cell_el, type);
return cell_el;
}
CopyLet's start with adding new column, First will register a click event on the add column button
addColumnBtn.on("click", addColumn);
CopyThe add column button will call addColumn function it will handle adding new column to the dynamic table editor
If you arn't femailer with appendChild
method checkout this article By javascripttutorial
function addColumn() {
// Add a cell on the table head
$(".table thead tr").appendChild(createCell("th"));
// And add a cell on each row
$(".table tbody tr", true).forEach((row) => {
row.appendChild(createCell("td"));
});
}
CopyAnd this is How we are going to add new row to the table as you can see it is very easy
addRowBtn.on("click", addRow);
CopyIt creates a new row and then it loops over the cells in the table head and it adds a new cell to the new row after that will add the new row to the table body.
function addRow() {
const row = document.createElement("tr");
$(".table thead tr th", true).forEach((_) => {
row.append(createCell("td"));
});
$(".table tbody").appendChild(row);
}
CopyConclusion
I hope you learn some valuable today This post was meant to help you learn how to interact with the DOM and level up your skills with JavaScript and also open your eyes to the possibilities of what you can build with JavaScript