Five years ago, I set myself a challenge: create a simple social network that would function without JavaScript.
It was a radical choice, but one driven by a few key reasons.
- At the time, most web apps were SPAs, built entirely in JavaScript, as if it were the only way to make a modern app. I had been working on React frontends for the past three years, and honestly, I was tired of it. I wanted a simpler stack.
- I also wanted a single source of truth between backend and frontend. That meant rendering HTML from the server, a basic concept I’d learned back in the 2000s, now enjoying a quiet revival.
- And most of all, I wanted to build an app that was HTML-centric. Being deep in the JavaScript ecosystem made me feel like I was drifting away from the fundamentals of the web. I wanted to go back to its roots. To me, that starts with HTML.
I used Ruby on Rails, because I love using it. But any other server-rendered framework would have worked just as well.
I was so used to JavaScript doing everything that I immediately noticed its absence when building common components like dropdowns, modals, steppers, and carousels. But I stuck to my rule: no JavaScript to make things work. JavaScript would only enhance what was already functional.
This forced me to completely rethink how I built my app. Take animations, for example. We often default to JavaScript for animations, but CSS handles most use cases better: it’s more reliable, performant, and declarative.
Want to animate a dropdown opening? Just use the :checked state and a <label>-triggered checkbox.
<input type="checkbox" id="toggle" /> <label for="toggle">Menu</label> <div class="menu">...</div>
Then in CSS:
.menu { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; } #toggle:checked + label + .menu { max-height: 500px; }
No JS, fully accessible, works everywhere.
Or take dynamic content, like steppers. Instead of hiding and showing steps with JavaScript, just render different steps server-side based on a query parameter or path.
For example:
- /signup?step=1
- /signup?step=2
The layout stays the same; only the content changes. Cleaner. Easier to debug. And nothing breaks if JavaScript fails.
The more I followed this "no JavaScript unless absolutely necessary" rule, the more I realized how much could be done in simpler ways. And how much of what I thought was essential wasn't. I was writing less code, but getting better results, and the UI was just as functional. The experience was smoother, and my app was more maintainable.
For those unfamiliar: Hotwire is a set of tools for building reactive applications with little to no JavaScript. It includes:
- Turbo Drive: speeds up navigation by eliminating full page reloads.
- Turbo Frames: lets you update only parts of the page, and they can be lazy-loaded
- Turbo Streams: lets you perform simple page changes using just HTML
- Stimulus: augments your HTML as needed
Want to speed up navigation? Drop in Turbo Drive. Want a single component to update on a user action? Wrap it in a turbo-frame. That’s it: no custom javascript, no state management headaches. But Hotwire shines the brightest only if your app is already built to work without JavaScript. Then it truly becomes an enhancer.
Don’t get me wrong, I like JavaScript. I'm just not convinced it should be doing everything, from rendering HTML to running backend logic (though I’m fine if it can). To each their own. And I'm most definitely not in the camp that believes JavaScript is the only way to build a modern web app. For me, JavaScript is to HTML what a good spice is to an already great meal: it can elevate the experience, but it shouldn’t be the foundation.
Final Thoughts
Building without JavaScript wasn’t a regression. it felt more like a rediscovery: a return to performance, simplicity, and the web's original strengths. Now, before reaching for JavaScript, I always ask myself: Can I do this with plain HTML and CSS first?
Most of the time, I can. Chances are, you can too. And your app might just end up faster, lighter, and easier to build. Next time you reach for JavaScript, pause and ask: can HTML and CSS do the job? It's worth giving it a shot, and you might never look back.