Guide

Lifecycle and updates

Understand controller ownership, normalized options, refresh behavior, declarative mounting, and cleanup.

Controller lifecycle

const instance = ticker('#partners', { duration: 18 })

instance?.element
instance?.source
instance?.options

instance?.update({ duration: 28 })
instance?.refresh()
instance?.destroy()

The controller is element-scoped:

OperationWrapperObserversOriginal source
ticker()created or adoptedconnectedmoved inside generated content when wrapping is needed
update()preservedpreservedunchanged
refresh()preservedpreservedremeasured
destroy()removed when generateddisconnectedrestored at the wrapper position

destroy() is idempotent. After destruction, element is null; update() and refresh() become safe no-ops that return the same controller.

Update versus refresh

Use update() when options change:

instance?.update({
  direction: 'right',
  duration: 40,
  class: 'partners partners--muted',
})

Use refresh() when your application changes content or layout without changing options:

instance?.source.append(newPartnerLogo())
instance?.refresh()

ResizeObserver normally handles geometry changes. Automatic resize and intersection checks reuse clones when measurements and clone settings are unchanged. Explicit refresh always regenerates clones, even after content changes that preserve width, and cannot be superseded by an automatic check. It is useful immediately after batched DOM work, visibility changes, or custom font transitions.

Both standalone controllers and declaratively mounted tickers pause outside the viewport and while the document is hidden. Shared visibility and motion-preference listeners are removed when the last ticker is destroyed.

Declarative manager

mount() scans the document for [data-ticker] and .ticker-wrapper, observes inserted/removed markup, and listens for relevant page changes. refresh() remeasures all managed instances. unmount() removes manager listeners and destroys all tracked ticker state.

import { mount, refresh, unmount } from '@samline/ticker/vanilla'

mount()
refresh()
unmount()

The manager is browser-safe to import during server rendering: calls become no-ops when window or document is unavailable.

The page manager and controller factory share runtime tracking. Do not give both lifecycles ownership of the same wrapper. unmount() removes clones and observers but does not call a controller’s restoration closure, so retain and explicitly destroy() application-created controllers when their generated wrapper must be replaced by the original source.

Library and application responsibilities

Ticker provides the runtime; the application owns the content, controls and integration lifecycle.

ConcernTicker handlesYour application handles
FrameworksA DOM-based API with no framework dependenciesInitialize after mounting and clean up on unmount
Visual copiesHides clones from assistive technology and keyboard focusKeep the original content meaningful and accessible
PlaybackPauses off-screen and in hidden documentsProvide a pause control for continuous motion
Reduced motionRespects the system preferenceKeep static content readable and reachable
Layout and contentRemeasures on resizeRefresh after application-owned edits, even when width stays unchanged
DistributionESM, CommonJS and a browser globalLoad the stylesheet alongside the selected API
LicensingMIT-licensed runtimeRetain the license when redistributing