Button to progress bar

Change a button to a progress bar after it's been clicked

I designed an interface recently that was based around a single action per view. The user would tap a button, then the device would perform an action such as loading a cartridge or performing internal tests. When that action completed, the next view would load.

The interface was on a small tablet-sized screen. I needed to maximize the available screen space, keep the interface clean and uncluttered, and still provide feedback to the user about what the device was doing.

My solution was to use a ghost button that converts to a progress bar.

Example

Click button again to reset animation

The code is fairly straightforward. Just a simple button, styled as a "ghost button". I'm using a pseudo-element for the "spark", and using a css transition to animate it based on if it has the active class.

This assumes that you know how long the progress will be. If the progress timing is more variable, then you'll have to use another actual element, such as a span inside the button, and make that the spark to animate. Use something like this.setAttribute('style', 'transition: left ' + transitionTime), with transitionTime being whatever length of time you need.

<button class="progress">Load Cartridge</button>
.progress {
    padding: 1em 0;
    font-size: 3.6rem;
    width: 18ch;

    --button-color: rgba(255,255,255, .7);
    background: transparent;
    color: var(--button-color);
    border: 1px solid var(--button-color);
    border-radius: .35em;

    position: relative;
    transition: all .6s;
}

.progress:hover {
    --button-color: #fff;
}

.progress::before {
    content:'';
    width: 5px;
    height: 5px;
    border-radius: 8px;
    background: white;
    position: absolute;
    left: 0;
    bottom: -3px;
    box-shadow: 0 0 12px 4px #B3F0F5;
    opacity: 0;
}

.progress.active {
    border-radius: 0;
    border-color: transparent;
    border-bottom-color: var(--button-color);
}

.progress.active::before {
    transition: left 6s;
    opacity: 1;
    left: 100%;
}

.progress:focus {
    outline: none;
}
var buttons = document.querySelectorAll('.progress');

var setActive = function() {
    var $list = this.classList;

    if($list.contains('active')) {
        $list.remove('active');
        this.innerHTML = "Load Cartridge";
    } else {
       $list.add('active');
       this.innerHTML = "Loading...";
    }
};

for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', setActive, false);
}