JSFiddle - React, Tailwind, and code Playground
by oktaviardi pratama
HTML
<div class="pill-container">
<input type="checkbox" id="tabToggle" class="pill-toggle-input">
<div class="pill-labels">
<label for="tabToggle" class="pill-label" aria-pressed="true">Ringkasan</label>
<label for="tabToggle" class="pill-label" aria-pressed="false">Detail</label>
</div>
<div class="pill-indicator"></div>
</div>
CSS
.pill-container {
position: relative;
display: inline-flex;
width: 240px;
height: 48px;
background-color: #e5e7eb;
border-radius: 9999px;
overflow: hidden;
font-family: system-ui, sans-serif;
}
/* Hidden checkbox */
.pill-toggle-input {
position: absolute;
opacity: 0;
pointer-events: none;
}
/* Label wrapper — covers full pill */
.pill-labels {
display: flex;
width: 100%;
height: 100%;
z-index: 1;
}
.pill-label {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1rem;
cursor: pointer;
color: #6b7280;
transition: color 0.3s ease;
user-select: none;
}
.pill-label:hover {
color: #1d4ed8;
}
.pill-label.active {
color: #1d4ed8;
font-weight: 600;
}
/* The white sliding pill (indicator) */
.pill-indicator {
position: absolute;
top: 4px;
left: 4px;
width: calc(50% - 8px);
height: calc(100% - 8px);
background: white;
border-radius: 9999px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
transition: left 0.35s cubic-bezier(0.68, -0.55, 0.27, 1.55);
z-index: 0;
}
/* When checkbox is checked → move indicator to right */
.pill-toggle-input:checked ~ .pill-indicator {
left: calc(50% + 4px); /* 50% + left padding (4px) */
}
/* Optional: focus outline */
.pill-label:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
.pill-indicator {
box-shadow:
0 4px 12px rgba(0,0,0,0.08),
0 2px 4px rgba(0,0,0,0.04);
}
.pill-indicator:hover {
box-shadow:
0 6px 16px rgba(0,0,0,0.12),
0 3px 6px rgba(0,0,0,0.06);
}
JavaScript
const toggle = document.getElementById('tabToggle');
const labels = document.querySelectorAll('.pill-label');
toggle.addEventListener('change', () => {
labels.forEach((lbl, i) => {
lbl.setAttribute('aria-pressed', toggle.checked === (i === 1));
lbl.classList.toggle('active', toggle.checked === (i === 1));
});
});
// Initialize state
labels[0].classList.add('active');
labels[0].setAttribute('aria-pressed', 'true');
labels[1].setAttribute('aria-pressed', 'false');