How to Build Interactive Web Pages Without Using JavaScript
Hello my frontend developer friends, today i will be discussing an awesome thing with you guys which we could help you in writing less javascript code to create interactive elements.
- I will be using tailwind css v4 for the styling
- I'll be creating my code snippets on Scribbler.live first, which is a fantastic platform that allows you to run a JavaScript Notebook, Online Compiler, and Editor without the need for manual setup.
- Additionally, I am including a link to code snippets that includes all of the code examples so you can open the snippet and run it yourself to see the results.
- I will be using
scrib.show
from scribbler.live, it is equivalent toconsole.log
Lets dive in...
Table of contents
- How to create interactive elements without JS?
- Notification component
- Dropdown component
- Modal component
- Sidebar navigation component
- Conclusion
How to create interactive elements without JS?
We will be using few new css selectors which has good browser support now. Using these selectors in a creative way could help in creating many interactive elements like modal, dropdown, popup, sidebar nav, etc.
- has() - it allow us to check the states of the child elements and do the styling to the parent or child itself
- [&] - parent selector which allow us to select a element or state of element using class, ids, data attributes, etc and style itself or the child elements.
- Syntax:
<div class="has-[h2]:bg-slate-900>
<h2 id="note"></h2>
</div>
<div class="[&_.warning]:bg-warning-600>
<p id="warning"></h2>
</div>
Notification component
<div class="!p-1 rounded-xl bg-white flex justify-between items-center gap-x-5 has-checked:hidden mb-14">
<h2 class="!text-slate-900">This notification is interactive and could be closed without Javascript</h2>
<label for="close-btn" class="text-red-400 text-xl cursor-pointer">
X
<input id="close-btn" type="checkbox" class="appearance-none w-0 h-0 hidden" />
</label>
</div>
- This is a simple logic, here we are checking on the parent element that if it has an input with checked state, then hide the entire element. Clicking the "X" will check the input and hide the element just like a notification element.
Dropdown component
<div class="!p-2 rounded-xl bg-white h-12 overflow-hidden has-checked:h-fit has-checked:overflow-visible w-fit mb-14">
<div class="flex justify-between items-center gap-x-5">
<label for="dropdown-btn" class="text-blue-400 text-xl cursor-pointer">
Dropdown
<input id="dropdown-btn" type="checkbox" class="appearance-none w-0 h-0 hidden" />
</label>
</div>
<ul class="mt-5 space-y-2">
<li>Content 1</li>
<li>Content 2</li>
<li>Content 3</li>
<li>Content 4</li>
<li>Content 5</li>
</ul>
</div>
- In the dropdown component, we will have a initial height just to show the dropdown heading, when we check the input, it will increase the height of the parent element showing the dropdown content. On clicking it again will uncheck the input and hide the content.
Modal component
<div class="[&:has(.modal-btn:checked)_.modal-content]:!block [&:has(.modal-btn:checked)_.modal-backdrop]:!block ">
<div class="flex justify-between items-center gap-x-5">
<label for="modal-btn" class="text-blue-400 text-xl cursor-pointer">
<span class="right-arrow">Open modal</span>
<input id="modal-btn" type="checkbox" class="appearance-none w-0 h-0 hidden modal-btn" />
</label>
</div>
<div class="hidden fixed z-20 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 modal-content bg-white w-1/2 h-40 rounded-xl">
<div class="absolute right-3 top-3 flex justify-between items-center gap-x-5">
<label for="modal-btn" class="text-blue-400 text-xl cursor-pointer">
<span class="text-red-500">X</span>
<input id="modal-btn" type="checkbox" class="appearance-none w-0 h-0 hidden" />
</label>
</div>
<div class="p-3 space-y-3">
<h2>Modal without javascript</h2>
<p>This modal is created with tailwind css has selector and no javascript is used for the interactivity</p>
</div>
</div>
<div class="hidden fixed z-10 inset-0 bg-slate-900/50 modal-backdrop"></div>
</div>
- This one is a bit tricky, here we are combining parent selector and has selector to check if the parent element has an input with class name "modal-btn" and if it is checked then show the content with class name "modal-content".
- Inside the modal content, we have another input checkbox with same class name, clicking it will uncheck the input and close the modal.
- We also has a backdrop element covering the entire screen when the modal is visible, it is also shown using the same way as modal.
- Breakdown of the classname: [&:has(.modal-btn:checked)_.modal-content]
- [&:has(.modal-btn:checked)] - this part is used to check whether the element has input with class name modal-btn with a checked state
- _.modal-content - Here underscore ( _ ) checks the element at nested level, it is checking for the modal-content classname using ".modal-content" dot notation.
Sidebar navigation component
<div class="fixed top-5 left-0">
<div class="flex gap-x-5 transition-all duration-200 ease-in -translate-x-24 has-checked:translate-x-4 w-fit has-checked:[&_.left-arrow]:block has-checked:[&_.right-arrow]:hidden">
<div class="mt-5 space-y-2 bg-slate-100 p-3 rounded-xl">
<ul class="space-y-5 max-h-60 overflow-auto">
<li>Content 1</li>
<li>Content 2</li>
<li>Content 3</li>
<li>Content 4</li>
<li>Content 5</li>
<li>Content 6</li>
<li>Content 7</li>
</ul>
</div>
<div class="absolute -right-10 flex justify-between items-center gap-x-5">
<label for="sidebar-btn" class="text-blue-400 text-xl cursor-pointer">
<span class="right-arrow text-xl">→</span>
<span class="left-arrow text-xl hidden">←</span>
<input id="sidebar-btn" type="checkbox" class="appearance-none w-0 h-0 hidden" />
</label>
</div>
</div>
</div>
- This one is also a simple one, here we are setting the translate x property with negative value to move it outside the screen on the left side. When we click the right arrow icon, it will check the input and add the positive translate x value to make it visible on the screen.
-
has-checked:[&_.left-arrow]:block has-checked:[&_.right-arrow]:hidden
- These classes just hide and show the left/right arrows based on the sidebar visibility.
Check out all the examples on scribbler.live and run it yourself to see the output from each of the examples above
🎯 Conclusion
Handling interactivity without javascript is kind of difficult task and we should be using javascript in case of complex elements having multiple operations doing with interactivity. We could use no-js approach for simpler elements like dropdown and notification elements.
That's it for this post, Let me know if i could do any improvements in this article. Also, do check Scribbler.live website.
You can contact me on -
Instagram - https://www.instagram.com/supremacism__shubh/
LinkedIn - https://www.linkedin.com/in/shubham-tiwari-b7544b193/
Email - [email protected]
You can help me with some donation at the link below Thank you👇👇
https://www.buymeacoffee.com/waaduheck
Also check these posts as well

Button Component with CVA and Tailwind
Shubham Tiwari ・ Feb 12 '24
