<form>
<h2>Radio Buttons</h2>
<span id="fill" class="radio-ghost-fill"></span>
<label>
<input name="items" type="radio" />
<span class="radio-ghost"></span>
Item one
</label>
<label>
<input name="items" type="radio" />
<span class="radio-ghost"></span>
Item two
</label>
<label>
<input name="items" type="radio" />
<span class="radio-ghost"></span>
Item three
</label>
</form>
html {
--accent: #0f03c2;
--dark-accent: #0a0644;
}
body {
min-height: 100vh;
font-family: 'Roboto', sans-serif;
font-size: 15px;
color: var(--dark-accent);
background: #ffffff;
overflow: hidden;
}
form {
display: flex;
align-items: center;
justify-content: center;
width: 250px;
min-height: 100vh;
margin: auto;
flex-direction: column;
}
h2, h1 {
flex-shrink: 0;
font-weight: 500;
}
h1 {
font-size: 1.35em;
}
h2 {
width: 100%;
padding-top: 20px;
font-size: 1.2em;
}
label {
position: relative;
flex-shrink: 0;
transition: all 200ms ease-in;
display: flex;
align-items: center;
cursor: pointer;
height: 50px;
width: 100%;
padding: 0 10px;
border-radius: 8px;
border: 1px solid transparent;
margin-bottom: 5px;
font-weight: 500;
}
input[type='radio'], input[type='checkbox'] {
position: absolute;
opacity: 0;
}
.radio-ghost {
position: relative;
display: block;
width: 18px;
height: 18px;
border-radius: 18px;
border: 3px solid var(--accent);
margin-right: 10px;
}
.radio-ghost-fill {
position: absolute;
transition: all 250ms ease-in-out;
transform: scale(.2);
content: '';
width: 14px;
height: 14px;
background-color: var(--accent);
border-radius: 7px;
opacity: 0;
}
document.addEventListener('DOMContentLoaded', function () {
var radioButtons = document.getElementsByName('items');
var fill = document.getElementById('fill');
var hasSelection = false;
var prevRect, checkedButton;
function updateOffsets() {
if (checkedButton) {
var rect = checkedButton.nextElementSibling.getBoundingClientRect();
fill.style.transition = 'none';
fill.style.top = (rect.top + 5 + document.body.scrollTop) + 'px';
fill.style.left = (rect.left + 5 + document.body.scrollLeft) + 'px';
prevRect = rect;
}
}
window.addEventListener('resize', updateOffsets);
window.addEventListener('scroll', updateOffsets);
document.addEventListener('change', function (e) {
if (e.target.name === 'items') {
Array.from(radioButtons).forEach(function (radioButton) {
if (radioButton.checked) {
checkedButton = radioButton;
radioButton.parentNode.className = 'selected';
var rect = radioButton.nextElementSibling.getBoundingClientRect();
if (!hasSelection) {
fill.style.transition = 'none';
fill.style.top = (rect.top + 5 + document.body.scrollTop) + 'px';
fill.style.left = (rect.left + 5 + document.body.scrollLeft) + 'px';
fill.style.transform = 'scale(.2)';
setTimeout(function () {
fill.style.transition = '';
fill.style.opacity = 1;
fill.style.transform = 'scale(1)';
}, 25);
} else {
fill.style.transition = 'none';
fill.style.top = (rect.top + 5 + document.body.scrollTop) + 'px';
fill.style.left = (rect.left + 5 + document.body.scrollLeft) + 'px';
fill.style.transform = 'scale(1) translateY(' + (0 - (rect.top - prevRect.top - 5)) + 'px)';
setTimeout(function () {
fill.style.transition = '';
fill.style.opacity = 1;
fill.style.transform = 'scale(1) translateY(0px) translateX(0px)';
}, 25);
}
hasSelection = true;
prevRect = rect;
} else {
radioButton.parentNode.className = '';
}
});
return;
}
});
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.