In this article, we’ll build a Dynamic Switch component in pure HTML, CSS, and JavaScript, featuring:
- A fluid sliding background highlight
- Full keyboard accessibility
- Clean, scalable structure
- Support for unlimited labels
- Easily reusable component wrapper
Let’s break down how it works and how you can implement it in your project.
🔧 What we're building
A smooth switch bar where clicking any label moves a highlight background behind it — similar to modern admin dashboards. The active label updates visually, and the sliding indicator gives a premium feel.
🧱 Step 1: HTML Structure
We wrap our text-switch labels inside a container using data attributes for easy JS targeting.
<div data-text-switch-wrapper>
<span data-text-switch-bg></span>
<label data-text-switch data-text-switch-active>Overview</label>
<label data-text-switch>Details</label>
<label data-text-switch>Analytics</label>
<label data-text-switch>Reports</label>
<label data-text-switch>Activity</label>
<label data-text-switch>Settings</label>
<label data-text-switch>Performance</label>
<label data-text-switch>Notifications</label>
<label data-text-switch>Summary</label>
<label data-text-switch>History</label>
</div>Why data-attributes?
- Keep JavaScript independent of class names
- Make the component reusable
- Maintain clean separation between logic and style
🎨 Step 2: Styling the Component
We use CSS to define the layout and the animated background.
Key parts:
Wrapper
[data-text-switch-wrapper] {
display: flex;
border: 1px solid var(--dark);
border-radius: 8px;
padding: 8px;
position: relative;
align-items: center;
}Labels
[data-text-switch] {
height: 34px;
line-height: 34px;
padding: 0 8px;
cursor: pointer;
z-index: 1;
}Sliding Background
[data-text-switch-bg] {
position: absolute;
top: 4px;
height: 34px;
background: var(--primary);
border-radius: 4px;
transition: all 0.3s linear;
z-index: 0;
}This background moves dynamically to match whichever label is active.
⚙️️️️ Step 3: Javascript - Handling Interaction
The JavaScript is fully vanilla and uses event delegation.
Highlighting Logic
We calculate the position and size of the active label and apply it to the background:
const highlightTextSwitchBG = (activeEl) => {
const parent = activeEl.parentElement;
const bg = parent.querySelector("[data-text-switch-bg]");
const parentRect = parent.getBoundingClientRect();
const activeRect = activeEl.getBoundingClientRect();
bg.style.left = (activeRect.left - parentRect.left) + "px";
bg.style.top = (activeRect.top - parentRect.top) + "px";
bg.style.width = activeRect.width + "px";
bg.style.height = activeRect.height + "px";
parent.querySelectorAll("[data-text-switch]")
.forEach(sw => sw.removeAttribute("data-text-switch-active"));
activeEl.setAttribute("data-text-switch-active", "");
};Initialization
On page load, we highlight whichever tab has the data-text-switch-active attribute.
textSwitchWrappers.forEach(wrapper => {
const activeSwitch = wrapper.querySelector("[data-text-switch-active]");
highlightTextSwitchBG(activeSwitch);
});Click Handling
wrapper.addEventListener("click", (e) => {
if (e.target.hasAttribute("data-text-switch")) {
highlightTextSwitchBG(e.target);
}
});✨Final Result
You now have a:
✔ Lightweight
✔ Framework-free
✔ Smooth animated
✔ Accessibility-friendly
✔ Reusable
Dynamic Text Switch UI Component ready for any dashboard or tab-based layout.
Here’s how it works :
This pattern can be wrapped into a JS module, reused across projects, or extended into a full tab-view rendering system.
If you enjoyed this post or have any feedback, feel free to connect with me:
- 💼 LinkedIn — Let’s network and share ideas!
- 👨💻 GitHub — Check out more of my projects and code examples.
- If you enjoyed my content or want to support my writing journey, please take a moment to follow me on Medium. I regularly share insights on JavaScript, modern frontend development, and practical dev tricks you can use in real projects.
🔗 Read the original article on Medium:
❤️ Follow me on Medium for more:
