DEV Community

Cover image for How to Build Interactive Web Pages Without Using JavaScript
Shubham Tiwari
Shubham Tiwari

Posted on

68 7 5 4 6

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 to console.log

Lets dive in...
Table of contents

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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">&#x2192;</span>
            <span class="left-arrow text-xl hidden">&#x2190;</span>
            <input id="sidebar-btn" type="checkbox" class="appearance-none w-0 h-0 hidden" />
          </label>
        </div>
      </div>
</div>
Enter fullscreen mode Exit fullscreen mode
  • 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




Image of Timescale

PostgreSQL for Agentic AI — Build Autonomous Apps on One Stack

pgai turns PostgreSQL into an AI-native database for building RAG pipelines and intelligent agents. Run vector search, embeddings, and LLMs—all in SQL

Build Today

Top comments (11)

Collapse
 
tracygjg profile image
Tracy Gilmore • Edited

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

Collapse
 
dansasser profile image
Daniel T Sasser II

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.

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari

Astro is Awesome specially their island architecture feature

Thread Thread
 
dansasser profile image
Daniel T Sasser II

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.

Collapse
 
tracygjg profile image
Tracy Gilmore

Bonus feature, no bundling.

Collapse
 
jonrandy profile image
Jon Randy 🎖️

I will be using tailwind css v4 for the styling

Then you'll be using JS 😉

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari

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🥂

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

If you're building an interactive web page without JS, you should have no use for a bundler 😉

Thread Thread
 
shubhamtiwari909 profile image
Shubham Tiwari

👍

Collapse
 
ngdangtu profile image
Đăng Tú

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 -_-

Collapse
 
shubhamtiwari909 profile image
Shubham Tiwari

@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.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay