Choosing the Right Pagination Type for Swiper.js
Learn how to choose between Swiper’s bullets, fraction, progressbar, or custom pagination based on UI space, feedback needs, and accessibility work, with a ready‑to‑run example and verification steps.
17 Aug 2026, 07:27 UTC

Problem and Takeaway
When building a carousel with Swiper.js you must decide which pagination style to show. The choice affects how much screen space the indicator uses, how quickly users can grasp their position, and whether the indicator meets accessibility needs. The useful takeaway is: match the pagination type to your UI constraints, the amount of feedback users need, and the accessibility work you are willing to do.
Decision Constraints
Before selecting a type, answer these three questions:
- Available UI space: Do you have room for a row of dots, or must the indicator stay compact?
- Feedback granularity: Do users need to know the exact slide number, or is a sense of progress enough?
- Accessibility responsibility: Are you prepared to add ARIA labels and roles for a custom indicator, or do you rely on Swiper’s built‑in accessibility?
Supported Pagination Options
| Type | HTML Output (default) | Space Usage | Position Feedback | Accessibility (out‑of‑the‑box) |
|---|---|---|---|---|
| Bullets | <span class="swiper-pagination-bullet"></span> repeated per slide | Linear with slide count (can become wide) | Exact slide via active bullet | Buttons with role="button" and aria-label indicating slide index |
| Fraction | <span class="swiper-pagination-fraction">{{current}} / {{total}}</span> | Fixed, minimal | Exact slide numbers (requires reading two numbers) | Live region announcing current/total when changed |
| Progressbar | <div class="swiper-pagination-progressbar-fill"></div> | Fixed, thin bar | Relative progress (0‑100%) – no exact slide number | Bar treated as presentational; no slide‑specific announcement |
| Custom | Any markup you provide | Depends on your design | Depends on your implementation | You must add ARIA attributes yourself |
Trade‑offs
- Bullets – Intuitive and clickable, but with many slides the row can overflow or wrap, hurting layout on narrow viewports.
- Fraction – Saves space and always shows the exact slide/total, yet users must parse two numbers to gauge position quickly.
- Progressbar – Gives a smooth, continuous sense of progress with minimal space, but hides the exact slide index, which can be problematic for tasks that require direct jump to a specific slide.
- Custom – Full visual freedom to match brand or design system, but you inherit the burden of ensuring keyboard operability, correct ARIA roles, labels, and live updates.
Concrete Implementation
Below is a minimal example that shows how to initialize Swiper with each pagination type, how to switch types safely, and what to inspect to verify the result.
HTML Structure
<!-- Container for the slider -->
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
<div class="swiper-slide">Slide 4</div>
<div class="swiper-slide">Slide 5</div>
</div>
<!-- Pagination placeholder -->
<div class="swiper-pagination"></div>
</div>
JavaScript – Initializing with Bullets (default)
// Run after DOM is ready, no special permissions needed.
const swiper = new Swiper('.swiper-container', {
pagination: {
el: '.swiper-pagination',
type: 'bullets', // change to 'fraction', 'progressbar', or 'custom'
clickable: true
}
});
Switching Pagination Type After Init
Changing the type property on an existing instance does not update the DOM; the old pagination element remains orphaned. To avoid leftover nodes, destroy the instance and create a new one with the desired configuration:
function updatePagination(newType) {
if (swiper) swiper.destroy(true, true); // true = remove events, true = restore original styles
swiper = new Swiper('.swiper-container', {
pagination: { el: '.swiper-pagination', type: newType, clickable: true }
});
}
// Example usage:
// updatePagination('fraction');
Verification Steps
- Open browser DevTools (F12) and inspect the element with class
swiper-pagination. - Check for the expected child classes:
- Bullets: multiple
.swiper-pagination-bulletelements; the active one hasswiper-pagination-bullet-active. - Fraction: a single
.swiper-pagination-fractioncontaining something like2 / 5. - Progressbar: a single
.swiper-pagination-progressbar-fillwhose width changes as you slide. - Custom: your own markup; verify you added
role,aria-label, andaria-valuenow(or similar) as needed.
- Bullets: multiple
- Optionally run an accessibility audit (e.g.,
npm i -g axe-cli && axe run) or test with a screen reader to ensure the pagination announces slide index or progress.
Limitations and Practical Checks
- Bullets: With >10 slides the indicator may wrap or overflow on small screens. Check by resizing the viewport and verifying the pagination stays within the container bounds.
- Fraction: Provides exact numbers but no quick visual cue of progress. Verify by noting the fraction updates correctly after each slide change.
- Progressbar: Shows smooth fill but hides the exact slide number. Confirm by observing the fill width change proportionally to slide index.
- Custom: You must maintain accessibility yourself. A practical check is to inspect the DOM for appropriate ARIA attributes and to run an axe audit focused on the pagination region.
By following the decision constraints, reviewing the trade‑off table, and using the initialization/verification steps above, you can pick and confirm a pagination type that fits your design, space, and accessibility requirements.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.