HOW TO: Create the speed dial style floating action button from Material Design

Jhey Tompkins
5 min readJul 15, 2015

My last post was regarding a way in which to implement the ripple effect from Material Design for buttons in your sites and applications.

Coincidentally, since that post, material-design-lite(MDL) was released, a component library that allows you to easily add a Material Design look and feel to your sites and applications.

There are a good amount of components available and it couldn’t have come at a better time as I was looking to use the style in a project I am currently working on.

After experimenting with it and scouring the issue list, I noticed that the speed dial like floating action button wasn’t yet available (requested feature, issue here).

I’d had a go at putting one together for my current project before the MDL release. It wasn’t great so I set out to have another go at it.

For those in camp TL;DR; Here’s a demo!

The effect

If you refer to the components part of the Material Design spec you’ll not only see buttons, but also floating action button.

Within floating action button, there is a section for transitions, notably “speed dial” like transitions.

You can see a video of the effect here and read about it here.

Let’s get to it!

This approach

There are different approaches that could be taken to achieve the desired effect. In this solution I will create the markup required and take as much away from the JavaScript side of things as possible. In a different style approach more in line with MDL implementation style of some other components such as the MaterialMenu, we may opt to set a primary button and using specific attributes, use JavaScript to wrap specific elements with containers etc.

DOM

The desired effect requires us to use a floating action button(FAB) with a combination of other FABs(Speed dial FABS — SDFABs). I want to wrap the SDFABS in their own container(.mdl-button — fab_flinger-options) whilst wrapping both that container and our primary FAB in another container(.mdl-button — fab_flinger-container). This is necessary because I want to trigger behaviour based on toggling a class on the root container.

<div id=”fab_ctn” class=”mdl-button--fab_flinger-container”>
<button id=”fab_btn” class=”mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored”>
<i class=”material-icons”>add</i>
</button>
<div class=”mdl-button--fab_flinger-options”>
<button class=”mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect”>
<i class=”material-icons”>local_printshop</i>
</button>
<button class=”mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect”>
<i class=”material-icons”>content_copy</i>
</button>
<button class=”mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect”>
<i class=”material-icons”>content_paste</i>
</button>
</div>
</div>

In this example, I have one primary FAB and three SDFABs.

JavaScript

There isn’t much in terms of the script needed to operate our speed dial style floating action button.

All that is required is to toggle a class on/off for the root container based on user clicks of the primary FAB.

(function () {
var VISIBLE_CLASS = ‘is-showing-options’,
fab_btn = document.getElementById(‘fab_btn’),
fab_ctn = document.getElementById(‘fab_ctn’),
showOpts = function(e) {
var processClick = function (evt) {
if (e !== evt) {
fab_ctn.classList.remove(VISIBLE_CLASS);
fab_ctn.IS_SHOWING = false;
document.removeEventListener(‘click’, processClick);
}
};
if (!fab_ctn.IS_SHOWING) {
fab_ctn.IS_SHOWING = true;
fab_ctn.classList.add(VISIBLE_CLASS);
document.addEventListener(‘click’, processClick);
}
};
fab_btn.addEventListener(‘click’, showOpts);
}.call(this));

The process is that when a user clicks, if the speed dial isn’t open, open it and bind an event listener for the user clicking elsewhere on the page to close the speed dial. On the other hand, if the speed dial is open, close it and remove the event listener.

CSS

I opted to use Stylus as my CSS preprocessor for this particular implementation. I’d recommend using a preprocessor to save some of the lifting. Below is the compiled CSS minus vendor prefixes.

.mdl-button--fab_flinger-container {
position: fixed;
bottom: 10px;
right: 10px;
}
.mdl-button--fab_flinger-container.is-showing-options > button i {
transition: transform 0.1s linear;
transform: translate(-12px, -12px) rotate(45deg);
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options {
display: flex;
flex-direction: column-reverse;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button {
display: block;
animation-name: enter;
animation-fill-mode: forwards;
animation-duration: 0.1s;
transform-origin: bottom center;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(1) {
animation-delay: 0.1s;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(2) {
animation-delay: 0.2s;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(3) {
animation-delay: 0.3s;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(4) {
animation-delay: 0.4s;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(5) {
animation-delay: 0.5s;
}
.mdl-button--fab_flinger-container.is-showing-options .mdl-button--fab_flinger-options button:nth-of-type(6) {
animation-delay: 0.6s;
}
.mdl-button--fab_flinger-container .mdl-button--fab_flinger-options {
position: absolute;
bottom: 100%;
margin-bottom: 10px;
}
.mdl-button--fab_flinger-container .mdl-button--fab_flinger-options button {
transform: scale(0);
display: none;
}
@keyframes enter {
from {
transform: scale(0);
}
to {
transform: scale(0.8);
}
}

I made use of loops to create animation delays on the SDFABs. An alternative would be to do this with JavaScript but as the Material Design spec says their should be no more than 6 SDFABs, I think a CSS solution suffices and takes some burden away from writing JavaScript to deal with the behaviour.

Other things to note would be the use of flex-direction to get the animation delays to work in the correct order on the correct children.

Here is my Stylus code;

positioning = 10px
transitionD = .1s
optScale = 0.8
.mdl-button--fab_flinger-container
position fixed
bottom positioning
right positioning
&.is-showing-options
& > button
i
transition transform transitionD linear
transform translate(-12px, -12px) rotate(45deg)
.mdl-button--fab_flinger-options
display flex
flex-direction column-reverse
button
for child in (1..6)
&:nth-of-type({child})
animation-delay (transitionD * child)
display block
animation-name enter
animation-fill-mode forwards
animation-duration transitionD
transform-origin bottom center
.mdl-button--fab_flinger-options
position absolute
bottom 100%
margin-bottom positioning
button
transform scale(0)
display none
@keyframes enter
from
transform scale(0)
to
transform scale(optScale)

To conclude

This time, I’ve explored a possible solution for implementing the speed dial style floating action button from the Material Design spec.

However, for some, including myself, it’s easier to see some code in action rather than read it, so feel free to check out the demo.

As always, any questions or suggestions, please feel free to leave a response or tweet me 🐦!

--

--

Jhey Tompkins
Jhey Tompkins

Written by Jhey Tompkins

I make awesome things for awesome people!

No responses yet