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 - shubhmtiwri00@gmail.com
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

Top comments (11)
Hi Shubham, I am on a similar no/low JS quest with a couple of my projects. Both projects are data-centric (CRUD) applications, which makes things easier. The driver for one app was to ensure business logic and state were maintained entirely on the server. The other project is just to exercise a new (to us) technology for a hobby project.
In both cases we are using HTMX to facilitate client-server interaction. Were we need to employ some presentation state to improve user experience we are using Alpine JS, again to keep the amount of bespoke JS to a minimum.
We are having to employ a 3rd-party UI library, which requires configuration via JS, to contain this we wrap them in Web Components based on Lit, which we have found to be very effective.
Best Regards
HTMX for the win!
Try it with Astro, you won't be disappointed.
I built the Astro SSR SPA Template that uses them both together.
Astro is Awesome specially their island architecture feature
Yes, it is. It has helped me out tremendously.
I spent 20 years developing websites and enterprise software with PHP. When I started looking for a JavaScript framework, I initially leaned toward NextJS. I still use NextJS on projects, especially those that involve PayloadCMS.
But then I discovered Astro and immediately fell in love with its template-like nature. The ability to use components from nearly any framework, such as React, Svelte, or Vue, made it an easy choice for me.
It's still the underdog. But I have high hopes for it.
Bonus feature, no bundling.
Then you'll be using JS 😉
With Tailwind V4 it is less or almost no JS shipped to the bundler as the configuration is done in a css file not JS file🥂
If you're building an interactive web page without JS, you should have no use for a bundler 😉
👍
I think moderators should be more strict on post like this... where is the part of no-js? I see a ton of js lib in here -_-
@ngdangtu
Which Js lib bro?
Tailwind CSS?
It's version 4 has no JS dependency and only css configuration is needed to add the classes
Which JS lib is used here bro?
And I am also the moderator for dev.to🫤
Some comments may only be visible to logged-in visitors. Sign in to view all comments.