Spoiler alert: I'm author of Grains.js. If you missed my previous article on Grains.js, please check it out here.
Now I want to show how to use g-class directive for switching classes dynamically based on state. If you're building interactive UIs with plain HTML and want smooth transitions, animations, or dynamic styling โ without using a full JS framework โ then you'll love how g-class directive works in Grains.js.
Letโs dive into a real-world example.
Note: It's best to utilize TailwindCSS to use ready-made styles via their classes.
g-classdirective has nothing to do with TailwindCSS, however. It only switches class names based on state. After that, you can use whatever you want.
โจ Animated Notification Example
Weโll build a notification box with:
- Visibility toggle
- Error/success state styles
- Shake animation for emphasis
You can try the live demo here.
You can see updated list of examples at https://github.com/mk0y/grains.js/tree/main/examples.
โ Setup
Add Grains.js and TailwindCSS to your page:
<script defer src="https://mk0y.github.io/grains.js/dist/grains.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
Remember, using cdn.tailwindcss.com is not for production environments. I'm using it only for presentational purposes - you should build your css file instead.
Next, add a simple @keyframes animation for shake:
<style>
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
.shake {
animation: shake 0.5s ease-in-out;
}
</style>
๐ง The Markup
<div
g-state="notifications"
g-init='{"isVisible": false, "isError": false, "isShaking": false}'
>
<div
g-class="[
'transform transition-all duration-300 ease-in-out',
'p-4 rounded-lg shadow-lg mb-4',
isVisible && 'translate-y-0 opacity-100',
!isVisible && 'translate-y-4 opacity-0',
isError && 'bg-red-100 text-red-700',
!isError && 'bg-green-100 text-green-700',
isShaking && 'shake'
]"
>
<p class="font-medium">Notification Message</p>
</div>
<div class="space-x-2">
<button g-on:click="toggleVisibility">Toggle Visibility</button>
<button g-on:click="toggleError">Toggle Error State</button>
<button g-on:click="triggerShake">Shake Animation</button>
</div>
</div>
โ๏ธ State Changers
Grains.js uses global pure functions to update state. Hereโs how we control the behavior:
<script>
window.toggleVisibility = (ctx) => {
ctx.set({ isVisible: !ctx.get("isVisible") });
};
window.toggleError = (ctx) => {
ctx.set({ isError: !ctx.get("isError") });
};
window.triggerShake = (ctx) => {
ctx.set({ isShaking: true });
setTimeout(() => ctx.set({ isShaking: false }), 500);
};
</script>
๐ก How g-class Works
- You pass an array of strings or expressions.
- Only truthy values are included in the final class list.
- This makes toggling animations, colors, and layout transitions declarative and simple.
In the example above, when isVisible is true, classes like translate-y-0 and opacity-100 are added. When false, it falls back to a faded, translated state โ giving a nice slide/fade transition.
๐ Wrap-Up
The g-class directive in Grains.js makes conditional styling effortless, and when combined with Tailwind and a few keyframes, you can build delightful UI transitions in plain HTML โ no frameworks or build steps required.
๐ Please let me know what you'd like to change or add as a next feature in the comments.
Thank you!
Top comments (0)