-
CSS pagination UI style animation
HTML
CSS
JavaScript
1
Classic numbered
‹
›
2
Minimal text + arrows
←
Page 1 of 12
→
3
Dot indicators
4
Pill / segmented
5
Load more
Load more results ↓
20 of 100 loaded
6
Compact jump-to-page
‹
of
12
›
7
Progress bar
‹ Prev
Step 4 of 12
Next ›
8
Bordered squares
9
Underline tabs
10
Stepper with labels
‹ Back
Next ›
:root { --ink: #1c1c1e; --muted: #151543; --line: #0b0b0c; --accent: #2f5233; --accent-ink: #f6f7f2; --surface: #ffffff; --bg: #fafaf8; } * { box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, sans-serif; background: var(--bg); color: var(--ink); margin: 0; padding: 40px 20px 80px; } h1 { text-align: center; font-size: 22px; margin: 0 0 4px; } p.sub { text-align: center; color: var(--muted); font-size: 13.5px; margin: 0 0 48px; } .demo { max-width: 640px; margin: 0 auto 56px; padding: 28px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; } .demo h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin: 0 0 20px; display: flex; align-items: center; gap: 8px; } .demo h2 .num { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; background: var(--accent); color: var(--accent-ink); font-size: 11px; font-weight: 600; } .row { display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap; } ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 4px; align-items: center; } button { font-family: inherit; cursor: pointer; } .btn { appearance: none; border: 1px solid var(--line); background: var(--surface); color: var(--ink); min-width: 34px; height: 34px; padding: 0 8px; border-radius: 8px; font-size: 13px; font-weight: 500; display: inline-flex; align-items: center; justify-content: center; transition: all .15s ease; font-variant-numeric: tabular-nums; } .btn:hover:not(:disabled):not(.active) { border-color: #c7c7cc; background: #f2f2f0; } .btn:active:not(:disabled) { transform: scale(0.94); } .btn:disabled { opacity: .35; cursor: not-allowed; } .btn.active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); } .ellipsis { min-width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); font-size: 13px; user-select: none; } /* 2. Minimal text + arrows */ .t2 .label { font-size: 13.5px; color: var(--ink); font-variant-numeric: tabular-nums; min-width: 90px; text-align: center; } .t2 .icon-btn { border: none; background: none; width: 32px; height: 32px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: var(--ink); } .t2 .icon-btn:hover:not(:disabled) { background: #f2f2f0; } .t2 .icon-btn:disabled { opacity: .3; cursor: not-allowed; } /* 3. Dots */ .t3 .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); border: none; padding: 0; transition: all .2s ease; } .t3 .dot.active { background: var(--accent); width: 22px; border-radius: 5px; } .t3 .dot:hover:not(.active) { background: #c7c7cc; } /* 4. Pill numbers */ .t4 ul { background: #f0f0ee; padding: 4px; border-radius: 999px; } .t4 .btn { border: none; border-radius: 999px; background: transparent; min-width: 32px; height: 32px; } .t4 .btn.active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); } .t4 .btn:hover:not(.active) { background: transparent; color: var(--accent); } /* 5. Load more */ .t5 .load-btn { border: 1px solid var(--line); background: var(--surface); color: var(--ink); padding: 10px 24px; border-radius: 999px; font-size: 13.5px; font-weight: 600; display: inline-flex; align-items: center; gap: 8px; transition: all .15s ease; } .t5 .load-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } .t5 .load-btn:disabled { opacity: .4; cursor: not-allowed; } .t5 .meter { width: 200px; height: 4px; background: var(--line); border-radius: 2px; margin: 14px auto 0; overflow: hidden; } .t5 .meter-fill { height: 100%; background: var(--accent); transition: width .25s ease; } .t5 .cap { text-align: center; font-size: 12px; color: var(--muted); margin-top: 8px; } /* 6. Compact jump input */ .t6 .jump { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); } .t6 input { width: 44px; height: 34px; text-align: center; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; font-family: inherit; color: var(--ink); } .t6 input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; } /* 7. Progress bar */ .t7-inner { display: flex; flex-direction: column; align-items: center; gap: 10px; } .t7 .bar { width: 100%; max-width: 400px; height: 6px; background: var(--line); border-radius: 3px; position: relative; overflow: hidden; } .t7 .fill { position: absolute; left: 0; top: 0; height: 100%; background: var(--accent); border-radius: 3px; transition: width .2s ease; } .t7 .controls { display: flex; align-items: center; gap: 16px; font-size: 13px; color: var(--muted); } .t7 .controls .btn { border: none; background: none; min-width: auto; padding: 0; color: var(--ink); font-weight: 600; height: auto; } .t7 .controls .btn:hover:not(:disabled) { color: var(--accent); background: none; } .t7 .controls .btn:disabled { opacity: .35; } /* 8. Bordered squares */ .t8 .btn { border-radius: 0; border-color: var(--ink); } .t8 ul { gap: 0; } .t8 .btn { margin-left: -1px; } .t8 .btn.active { background: var(--ink); border-color: var(--ink); color: #fff; z-index: 1; position: relative; } /* 9. Underline tabs */ .t9 ul { gap: 18px; } .t9 .btn { border: none; background: none; border-radius: 0; min-width: auto; padding: 4px 2px; border-bottom: 2px solid transparent; color: var(--muted); font-weight: 500; height: auto; } .t9 .btn:hover:not(.active) { color: var(--ink); background: none; } .t9 .btn.active { color: var(--accent); border-bottom-color: var(--accent); background: none; } /* 10. Stepper */ .t10-inner { display: flex; flex-direction: column; align-items: center; gap: 22px; } .t10 .steps { display: flex; align-items: center; } .t10 .step { display: flex; flex-direction: column; align-items: center; gap: 6px; position: relative; background: none; border: none; padding: 0; } .t10 .circle { width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid var(--line); background: var(--surface); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--muted); z-index: 1; transition: all .15s ease; } .t10 .step.done .circle { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); } .t10 .step.active .circle { border-color: var(--accent); color: var(--accent); } .t10 .step small { font-size: 10.5px; color: var(--muted); position: absolute; top: 36px; white-space: nowrap; } .t10 .connector { width: 44px; height: 1.5px; background: var(--line); transition: background .2s ease; } .t10 .connector.done { background: var(--accent); } .t10 .step-nav { display: flex; gap: 10px; } .t10 .step-nav .btn { height: 32px; padding: 0 14px; }
/* ---------- shared helper: windowed page range with ellipsis ---------- */ function pageRange(current, total, delta) { delta = delta || 1; const range = []; const withDots = []; let l; for (let i = 1; i <= total; i++) { if (i === 1 || i === total || (i >= current - delta && i <= current + delta)) range.push(i); } range.forEach((i) => { if (l) { if (i - l === 2) withDots.push(l + 1); else if (i - l > 2) withDots.push('...'); } withDots.push(i); l = i; }); return withDots; } /* ---------- 1. Classic numbered ---------- */ (function () { const TOTAL = 12; let current = 1; const list = document.getElementById('t1-list'); const prev = document.getElementById('t1-prev'); const next = document.getElementById('t1-next'); function render() { list.innerHTML = ''; pageRange(current, TOTAL).forEach((p) => { const li = document.createElement('li'); if (p === '...') { li.className = 'ellipsis'; li.textContent = '···'; } else { const btn = document.createElement('button'); btn.className = 'btn' + (p === current ? ' active' : ''); btn.textContent = p; btn.setAttribute('aria-label', 'Page ' + p); if (p === current) btn.setAttribute('aria-current', 'page'); btn.onclick = () => goTo(p); li.appendChild(btn); } list.appendChild(li); }); prev.disabled = current === 1; next.disabled = current === TOTAL; } function goTo(p) { current = Math.min(Math.max(p, 1), TOTAL); render(); } prev.onclick = () => goTo(current - 1); next.onclick = () => goTo(current + 1); render(); })(); /* ---------- 2. Minimal text + arrows ---------- */ (function () { const TOTAL = 12; let current = 1; const label = document.getElementById('t2-label'); const prev = document.getElementById('t2-prev'); const next = document.getElementById('t2-next'); function render() { label.textContent = 'Page ' + current + ' of ' + TOTAL; prev.disabled = current === 1; next.disabled = current === TOTAL; } prev.onclick = () => { if (current > 1) { current--; render(); } }; next.onclick = () => { if (current < TOTAL) { current++; render(); } }; render(); })(); /* ---------- 3. Dots ---------- */ (function () { const TOTAL = 5; let current = 0; const wrap = document.getElementById('t3-dots'); function render() { wrap.innerHTML = ''; for (let i = 0; i < TOTAL; i++) { const dot = document.createElement('button'); dot.className = 'dot' + (i === current ? ' active' : ''); dot.setAttribute('aria-label', 'Slide ' + (i + 1)); dot.onclick = () => { current = i; render(); }; wrap.appendChild(dot); } } render(); })(); /* ---------- 4. Pill / segmented ---------- */ (function () { const TOTAL = 4; let current = 1; const list = document.getElementById('t4-list'); function render() { list.innerHTML = ''; for (let p = 1; p <= TOTAL; p++) { const li = document.createElement('li'); const btn = document.createElement('button'); btn.className = 'btn' + (p === current ? ' active' : ''); btn.textContent = p; btn.onclick = () => { current = p; render(); }; li.appendChild(btn); list.appendChild(li); } } render(); })(); /* ---------- 5. Load more ---------- */ (function () { const TOTAL_ITEMS = 100; const STEP = 20; let loaded = 20; const btn = document.getElementById('t5-btn'); const fill = document.getElementById('t5-fill'); const cap = document.getElementById('t5-cap'); function render() { const pct = Math.min((loaded / TOTAL_ITEMS) * 100, 100); fill.style.width = pct + '%'; cap.textContent = loaded + ' of ' + TOTAL_ITEMS + ' loaded'; if (loaded >= TOTAL_ITEMS) { btn.disabled = true; btn.textContent = 'All results loaded'; } } btn.onclick = () => { loaded = Math.min(loaded + STEP, TOTAL_ITEMS); render(); }; render(); })(); /* ---------- 6. Compact jump-to-page ---------- */ (function () { const TOTAL = 12; let current = 1; const input = document.getElementById('t6-input'); const prev = document.getElementById('t6-prev'); const next = document.getElementById('t6-next'); document.getElementById('t6-total').textContent = TOTAL; function render() { input.value = current; prev.disabled = current === 1; next.disabled = current === TOTAL; } function goTo(p) { p = Math.min(Math.max(parseInt(p, 10) || 1, 1), TOTAL); current = p; render(); } prev.onclick = () => goTo(current - 1); next.onclick = () => goTo(current + 1); input.addEventListener('change', () => goTo(input.value)); input.addEventListener('keydown', (e) => { if (e.key === 'Enter') goTo(input.value); }); render(); })(); /* ---------- 7. Progress bar ---------- */ (function () { const TOTAL = 12; let current = 4; const fill = document.getElementById('t7-fill'); const label = document.getElementById('t7-label'); const prev = document.getElementById('t7-prev'); const next = document.getElementById('t7-next'); function render() { fill.style.width = (current / TOTAL) * 100 + '%'; label.textContent = 'Step ' + current + ' of ' + TOTAL; prev.disabled = current === 1; next.disabled = current === TOTAL; } prev.onclick = () => { if (current > 1) { current--; render(); } }; next.onclick = () => { if (current < TOTAL) { current++; render(); } }; render(); })(); /* ---------- 8. Bordered squares ---------- */ (function () { const TOTAL = 5; let current = 2; const list = document.getElementById('t8-list'); function render() { list.innerHTML = ''; for (let p = 1; p <= TOTAL; p++) { const li = document.createElement('li'); const btn = document.createElement('button'); btn.className = 'btn' + (p === current ? ' active' : ''); btn.textContent = p; btn.onclick = () => { current = p; render(); }; li.appendChild(btn); list.appendChild(li); } } render(); })(); /* ---------- 9. Underline tabs ---------- */ (function () { const TOTAL = 5; let current = 1; const list = document.getElementById('t9-list'); function render() { list.innerHTML = ''; for (let p = 1; p <= TOTAL; p++) { const li = document.createElement('li'); const btn = document.createElement('button'); btn.className = 'btn' + (p === current ? ' active' : ''); btn.textContent = p; btn.onclick = () => { current = p; render(); }; li.appendChild(btn); list.appendChild(li); } } render(); })(); /* ---------- 10. Stepper with labels ---------- */ (function () { const STEPS = ['Cart', 'Shipping', 'Payment', 'Confirm']; let current = 1; // 0-indexed step const wrap = document.getElementById('t10-steps'); const prev = document.getElementById('t10-prev'); const next = document.getElementById('t10-next'); function render() { wrap.innerHTML = ''; STEPS.forEach((name, i) => { const step = document.createElement('button'); step.className = 'step' + (i < current ? ' done' : '') + (i === current ? ' active' : ''); step.innerHTML = '
' + (i < current ? '✓' : i + 1) + '
' + name + '
'; step.onclick = () => { current = i; render(); }; wrap.appendChild(step); if (i < STEPS.length - 1) { const connector = document.createElement('div'); connector.className = 'connector' + (i < current ? ' done' : ''); wrap.appendChild(connector); } }); prev.disabled = current === 0; next.disabled = current === STEPS.length - 1; } prev.onclick = () => { if (current > 0) { current--; render(); } }; next.onclick = () => { if (current < STEPS.length - 1) { current++; render(); } }; render(); })();
Live Preview