ライブデモ Live Demo
ナビゲーションはシンプルな <button> 要素で構成され、.tabs__indicator スパンがアクティブなタブの下でスライドします。インジケーターのタイミングはカスタムプロパティで簡単に調整できます。
The navigation consists of plain <button> elements while a .tabs__indicator span slides under the active tab. Indicator timing is exposed as a custom property for easy tuning.
AI向け説明 AI Description
ボタンと絶対位置のインジケーターを同一コンテナに配置します。ホバー/クリック時に`offsetLeft`/`offsetWidth`を計算し、`transform`と`width`を更新します。`is-active`を切り替えてテキスト色を同期させ、アニメーション継続時間は設定可能に保ちます。
Place buttons and an absolutely positioned indicator under the same container. On hover/click, compute `offsetLeft` / `offsetWidth` and update `transform` plus `width`. Toggling `is-active` keeps the text color in sync while the animation duration stays configurable.
調整可能パラメータ Adjustable Parameters
- --indicator-duration インジケーターアニメーションの継続時間 indicator animation duration
- indicator gradient グラデーションをブランドカラーに合わせる match the gradient to brand colors
- gap / padding 間隔とクリックエリアの調整 tune spacing and hit area
- focus styles キーボードユーザー用のフォーカスリングを追加 add visible focus rings for keyboard users
実装 Implementation
HTML + CSS + JS
<nav class="tabs" data-tabs>
<button class="is-active">Overview</button>
<button>Docs</button>
<button>API</button>
<span class="tabs__indicator"></span>
</nav>
<style>
.tabs {
position: relative;
display: inline-flex;
gap: 18px;
}
.tabs button {
border: none;
background: transparent;
font-weight: 600;
padding: 8px 0;
color: #4b5178;
}
.tabs button.is-active {
color: #181d40;
}
.tabs__indicator {
position: absolute;
bottom: 0;
height: 3px;
border-radius: 999px;
background: linear-gradient(90deg, #5c6ac4, #8c6ff7);
transition: transform var(--indicator-duration, 0.45s) ease,
width var(--indicator-duration, 0.45s) ease;
}
</style>
<script>
const tabs = document.querySelector("[data-tabs]");
const indicator = tabs.querySelector(".tabs__indicator");
const buttons = [...tabs.querySelectorAll("button")];
function moveIndicator(target) {
indicator.style.transform = `translateX(${target.offsetLeft}px)`;
indicator.style.width = `${target.offsetWidth}px`;
}
buttons.forEach((button) => {
button.addEventListener("click", () => {
buttons.forEach((b) => b.classList.remove("is-active"));
button.classList.add("is-active");
moveIndicator(button);
});
button.addEventListener("mouseenter", () => moveIndicator(button));
});
moveIndicator(buttons[0]);
</script>
React (JSX + CSS)
// react/N-001.jsx
import { useRef, useState, useEffect } from "react";
import "./N-001.css";
const tabs = ["Overview", "Docs", "API", "Changelog"];
export default function SlidingUnderlineTabs() {
const containerRef = useRef(null);
const [activeIndex, setActiveIndex] = useState(0);
useEffect(() => {
const container = containerRef.current;
const indicator = container?.querySelector(".tabs__indicator");
const buttons = container?.querySelectorAll("button");
if (!indicator || !buttons?.[activeIndex]) return;
const target = buttons[activeIndex];
indicator.style.transform = `translateX(${target.offsetLeft}px)`;
indicator.style.width = `${target.offsetWidth}px`;
}, [activeIndex]);
return (
<div className="tabs" ref={containerRef}>
{tabs.map((label, index) => (
<button
key={label}
className={index === activeIndex ? "is-active" : ""}
onMouseEnter={() => setActiveIndex(index)}
onClick={() => setActiveIndex(index)}
>
{label}
</button>
))}
<span className="tabs__indicator" />
</div>
);
}
/* react/N-001.css */
.tabs {
position: relative;
display: inline-flex;
gap: 18px;
}
.tabs button {
border: none;
background: transparent;
font-weight: 600;
color: #4b5178;
padding: 8px 0;
cursor: pointer;
}
.tabs button.is-active {
color: #181d40;
}
.tabs__indicator {
position: absolute;
bottom: 0;
height: 3px;
border-radius: 999px;
background: linear-gradient(90deg, #5c6ac4, #8c6ff7);
transition: transform var(--indicator-duration, 0.45s) ease,
width var(--indicator-duration, 0.45s) ease;
}
AIへの指示テンプレート AI Prompt Template
以下のテンプレートをコピーしてAIアシスタントに貼り付けると、このパターンの実装を依頼できます。 Copy the template below and paste it into your AI assistant to request an implementation of this pattern.
ノート & バリエーション Notes & Variations
スクロール可能なナビバーやレスポンシブなドロップダウンには、同じマークアップに overflow-x: auto を追加するか、ボタンを select オプションに変換してインジケーターロジックを再利用してください。
For scrollable nav bars or responsive dropdown fallbacks, keep the same markup and add overflow-x: auto or convert buttons into select options while reusing the indicator logic.