It's the little things. Recently jhey.dev got the honor of making it onto whimsical.club. It's "A curated list of sites with an extra bit of fun".
What's whimsy? It's that little bit of fun we can add to our projects. Something that gives our audience a little insight into who we are. It's also another way to connect with your viewers. Sarah Drasner summed this up well in a recent article.
"While we’re all laser-focused on shipping the newest feature with the hottest software and the best Lighthouse scores, I’ve been missing a bit of the joy on the web. Apps are currently conveying little care for UX, guidance, richness, and — well, for humans trying to communicate through a computer, we’re certainly bending a lot to… the computer."
So. Today we're going to add a confetti blast when users submit a form. It could be a little joy when someone signs up for your newsletter. This is what I'm using it for. I added it You can see it in action at jhey.dev.
Let's start with a form, a very basic form. For example, this form will take you to the sign-up for my newsletter.
<form class="whimsy-form" action="https://www.getrevue.co/profile/jh3y/add_subscriber" method="post" target="_blank">
<div class="whimsy-form__group">
<label>Email address</label>
<input type="email" required="true"/>
</div>
<div class="whimsy-form__actions">
<input type="submit" value="Subscribe"/>
</div>
</form>
Let's take that further and add some extra markup and styles to make it a little "friendlier". Here's a quick form we've put together with Tailwind.
At this point, it looks fine. You can always add a little "character" here with the copy you use. Use these opportunities to make a connection. "Want to stay in touch? I'd like to share things I learn with you" sounds better than "Sign up for my newsletter". Anyway, that's another post in itself!
But, we want confetti!
Let's hop into some JavaScript. We're going to use the canvas-confetti
package. It's perfect for our use case. You've got many options for grabbing this. We can use skypack
for our demos. You might want to install it in your project and import
it.
import confetti from 'https://cdn.skypack.dev/canvas-confetti
Then we need to grab the submit button for our form along with the form itself.
const FORM = document.querySelector('form')
const SUBMIT = FORM.querySelector('[type="submit"]')
Then tie up the confetti blast to our form submission.
FORM.addEventListener('submit', () => {
confetti()
})
Well. That works. But, not how we want it to. For one, we miss the confetti as the browser opens a new tab. When we return, we see the confetti. But, it blasts out from the middle of the screen.
Let's sort that out. We need to prevent the default action for the form from happening. We can preventDefault
on the event for that. And then, we will get the button position with getBoundingClientRect
. We can use that to determine where we want to fire the confetti from.
import confetti from 'https://cdn.skypack.dev/canvas-confetti'
const FORM = document.querySelector("form")
const SUBMIT = FORM.querySelector('[type="submit"]')
const onSubmit = e => {
e.preventDefault()
const BOUNDS = SUBMIT.getBoundingClientRect()
confetti({
origin: {
x: (BOUNDS.x + BOUNDS.width / 2) / window.innerWidth,
y: (BOUNDS.y + BOUNDS.height / 2) / window.innerHeight,
},
})
}
FORM.addEventListener('submit', onSubmit)
The last thing to do is submit our form after a desired delay. We could wait until the end of the confetti. But, around a second is likely enough.
setTimeout(() => FORM.submit(), 1000)
Putting it all together.
import confetti from 'https://cdn.skypack.dev/canvas-confetti'
const FORM = document.querySelector("form")
const SUBMIT = FORM.querySelector('[type="submit"]')
const onSubmit = e => {
e.preventDefault()
const BOUNDS = SUBMIT.getBoundingClientRect()
confetti({
origin: {
x: (BOUNDS.x + BOUNDS.width / 2) / window.innerWidth,
y: (BOUNDS.y + BOUNDS.height / 2) / window.innerHeight,
},
})
setTimeout(() => FORM.submit(), 1000)
}
FORM.addEventListener('submit', onSubmit)
Hurrah! 🎉 We have a little whimsy for our form.
It's worth exploring the docs for canvas-confetti
. You can tweak the settings to your tastes and generate different effects. One option we should pay attention to is disableForReducedMotion
. I'd recommend setting this to "true" so we respect users with vestibular disorders.
confetti({
disableForReducedMotion: true
})
Now we have some confetti, we could even take this a little further with some audio. Drop an audio
element into our markup and use the preload
attribute.
<audio src="https://assets.codepen.io/605876/horn.mp3" preload="auto"></audio>
Using preload
ensures that the audio is ready for playback as soon as we hit our "Subscribe" button.
All we need to do is tie that into our "onSubmit" function. Grab the audio element and use the "play" method.
const AUDIO = FORM.querySelector('audio')
// Then inside "onSubmit"
AUDIO.play()
And there we have it. A whimsical sign up form that will give your users a little joy and something to remember when they submit a form. And you can take joy from knowing that you've shipped a little enhancement for your users. If a user disables JavaScript, your form still works without the bells and whistles.
I figured people might want a React version too. Here you go!
\ʕ •ᴥ•ʔ/
The same process but we can use useRef
to grab the element references.
That's it!
One way to add a little joy to your sites and apps. Think about combining this with some of the other things we've been looking at. You'll be well on your way to making awesome experiences for your users. As always, let me know what you think and see you for the next one!
Stay Awesome! ʕ •ᴥ•ʔ
Top comments (5)
Everyone loves a little bit of fun, and it definitely brings a human touch to the page. Now I have to add some confetti to a form today!
Do it! And then share that form with us! \ʕ •ᴥ•ʔ/
The audio, is that a seagull or cat? haha
Nice tutorial Jhey!
awesome!
\ʕ •ᴥ•ʔ/