I love JavaScript, but like every technology, it has its uses. Many developers overuse JavaScript and use it in situations where better solutions exist.
In the era of evergreen browsers, we can use new HTML/CSS relatively early after their release.
In today’s post, I will walk through the use case in which you can use HTML/CSS instead of writing JavaScript.
So, let's get started 👉
📦 Store state in the URL
This could be its own post; it is a pet peeve of mine. 😅
I have commented on too many pull requests about forms like the following, where the state is stored with the React.useState hook, when the best place for this data is the URL.
This way, you don’t lose your state when the page refreshes, you can send this URL to someone else, and the back button works.
Of course, it has its gotchas, like only updating the URL when the user stops typing in the search field, etc.
Even worse offenders are paginations or navigations, which are stored only locally, not reflecting which page the user is on.
🖱️Use CSS for hover effect
I have seen too much code like the following:
function MyButton() {
const [isHovered, setIsHovered] = useState(false);
const className = isHovered ? 'button button-hover' : 'button';
const onMouseEnter = () => setIsHovered(true);
const onMouseLeave = () => setIsHovered(false);
return (
<button
className={className}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}>Button</button>
);
}
Simple CSS can replace this:
.button:hover {
...code
}
And the button becomes just:
<button class="button" />
With hover, you can do a lot of cool things. My previous post about Tips for Tailwind CSS showed how to use “group” and “group-hover:” to style children when their parent is hovered.
<div class="group">
<span class="group-hover:bg-cloud">
When parent element (group) is hovered, I change background
</span>
<span>
I don't change color
</span>
</div>
📱Use CSS for responsive UI
CSS media queries and the upcoming container queries are the way to design responsive UIs.
In Angry Building, we have a lot of tables. One could say most of our UI is tables. 🙈
On mobile, those tables become a list of cards. We use a regular HTML table, which changes its “display” style on smaller screens.
The way this works is that on mobile screen sizes:
table elements switch to display block/flex.
I use the CSS “content” attribute and “attr” function trick to get cell titles
Here is the simplified CSS for this.
@media (max-width: 640px) {
.table-component,
.table-component thead,
.table-component tbody,
.table-component tfoot,
.table-component tr {
display: block;
}
.table-component tbody td {
display: flex;
}
.table-component tbody td:not(.actions):before {
content: attr(title);
flex: 0 1 35%;
display: block;
white-space: nowrap;
}
}
🗓️ Use a proper input type instead of a custom input
The input element has many types available and is very well supported.
The one I have used constantly recently is the “date” type; it has a built-in calendar. 📅
I like using <input type=”date” />
, instead of a JS calendar library because:
1️⃣ Accessible
2️⃣ Mobile friendly
3️⃣ All batteries included
🏆 No extra code
It's important to note that the “date” input type has limitations.. For instance, the popover calendar can't be styled to match a website and only allows for the selection of a single date.
There are many more useful types, like
range
color
datetime-local
month
time
week
… and more
I can’t tell you how much JavaScript code I have added to various projects to handle dates. In one project, there were four different calendar libraries. 🤦♂️
🔽 Use “details” HTML element
The <details> disclosure element has been supported in all major browsers for years.
It allows you to have expandable/collapsible content.
No JavaScript, no CSS—just HTML:
<details>
<summary>System Requirements</summary>
<p>
Requires a computer running an operating system.
The computer must have some memory and ideally some
kind of long-term storage.
</p>
</details>
With a bit of CSS, you can create a mobile hamburger menu like the one we have at Angry Building.
The code for this menu looks like the following:
HTML
<details>
<summary>
<svg class="open-hidden">...</svg>
<svg class="open-visible">...</svg>
</summary>
<ul>
<li><a>...</a></li>
<li><a>...</a></li>
...
</ul>
</details>
CSS
details[open] .open-hidden {
display: none;
}
details:not([open]) .open-visible {
display: none;
}
🖼️ Use “dialog” HTML element
The “dialog” HTML element is well supported. Its goal is to simplify creating modals and popovers.
It has some rough edges, but I still find it quite useful, reducing the amount of JavaScript I write.
1️⃣ Accessible
2️⃣ Build-in backdrop
3️⃣ Auto handling of forms (example: auto-focus)
4️⃣ Stops scrolling of back page
5️⃣ Auto handle of ESC
6️⃣ Style as you wish
You still need to write code to trigger the modal and close it when the user clicks on the backdrop.
Conclusion
There is no code faster than no code.
I love writing code, but I don’t like writing “boring code” that can be handled by the ecosystem I build on top of.
Whenever I can, I prefer to use elements provided by the system.
This is the reason I follow the Open UI project. I’m particularly excited about the Stylable Select Element. 🥹
What tips and tricks do you have for writing less JavaScript? 🤔
You can ping me on Threads, LinkedIn, Mastodon, Twitter, or just leave a comment below 📭
Great work as usual! :) Here’s my two cents:
World, please don't use :hover { cursor: pointer; } for the following elements:
- a (anchor tags)
- button
- input types: "button", "submit", "reset", "file"
- label associated with form controls
- summary elements used within details
Thank you! 😊