Skip to content

PageControl

PageControl (from scenerystack/sun) renders the classic iOS "row of dots" pagination indicator: one dot per page, with the current page's dot drawn distinctly. It's driven by two Properties rather than owning any paging state itself, which is exactly the shape Carousel exposes — pageNumberProperty and numberOfPagesProperty — so the two are typically constructed together, with PageControl reflecting (and, if interactive, controlling) which page of the carousel is showing.

ts
import { Carousel, PageControl, type CarouselItem } from 'scenerystack/sun';
import { Rectangle, VBox } from 'scenerystack/scenery';

const COLORS = [ '#5B9BD5', '#8FBF5B', '#D9782D', '#B05BD5', '#D5B15B' ];

const items: CarouselItem[] = COLORS.map( color => ( {
  createNode: () => new Rectangle( 0, 0, 50, 50, { fill: color, cornerRadius: 8 } )
} ) );

const carousel = new Carousel( items, {
  orientation: 'horizontal',
  itemsPerPage: 2,
  margin: 8
} );

const pageControl = new PageControl(
  carousel.pageNumberProperty,
  carousel.numberOfPagesProperty,
  {
    interactive: true,
    orientation: 'horizontal'
  }
);

const panel = new VBox( {
  spacing: 10,
  align: 'center',
  children: [ carousel, pageControl ]
} );

pageNumberProperty must be a settable TProperty<number> (not just readable) precisely because PageControl writes to it when interactive: true and a dot is clicked — Carousel.pageNumberProperty satisfies this directly.

Options

OptionDefaultEffect
interactivefalseWhether clicking a dot navigates to that page
orientation'horizontal''horizontal' (dots left-to-right) or 'vertical' (top-to-bottom); match your carousel's orientation
dotRadius3Radius of each dot
dotSpacing10Space between adjacent dots
lineWidth1Stroke width, if currentPageStroke/pageStroke are set
dotTouchAreaDilation / dotMouseAreaDilation4 / 4Pointer-area dilation beyond each dot's radius, when interactive
currentPageFill / currentPageStroke'black' / nullAppearance of the dot for the current page
pageFill / pageStroke'rgb( 200, 200, 200 )' / nullAppearance of every other dot

Dots are recreated whenever the page count changes

PageControl rebuilds its dots from scratch every time numberOfPagesProperty fires — including at construction — so it stays correct if a Carousel's visible item count changes at runtime (e.g. via Carousel.setItemVisible), without any extra wiring on your part.