Repeater

import "@taprootio/espalier/repeater";

<esp-repeater>

General-purpose virtualized repeater for rich repeated content such as cards, image rows, or other custom-element item layouts. Consumers provide the item renderer and own the visual design of each repeated item.

Because the list is virtualized, repeated item content is supplied through the renderItem property instead of light-DOM children. This lets the repeater create item DOM on demand as the user scrolls.

Use layout="grid" to opt into responsive card layouts. Consumers can provide a fixed fallback with grid-columns and override the live column count with --esp-repeater-grid-columns in media queries.

Use scroll-model="page" when the repeater should participate in the document's natural page scroll instead of owning a nested scrolling viewport. In page mode, list-height is ignored.

Examples

Basic image list

Cursor-paged image list

Grid mode with responsive columns

Properties

EspalierRepeater has the following properties:

virtualizerRef

containerRef

pageLoads

nextCursor

Type: string | null

lastObservedWidth

Type: number

observersAttached

Type: boolean

gridObserversAttached

Type: boolean

resolvedGridColumns

Type: number

memoizedGridRowsSource

Type: unknown[] | null

memoizedGridRowsColumns

Type: number

memoizedGridRows

Type: RepeaterGridRow<unknown>[]

hostAttributeObserver

Type: MutationObserver | null

resizeObserver

Type: ResizeObserver | null

viewportResizeListener

Type: (() => void) | null

pageScrollStabilizerActive

Type: boolean

activePageScrollStabilizer

Type: PageScrollStabilizer | null

isAdjustingHeight

Type: boolean

pendingHeightRetry

Type: boolean

heightRetryObserver

Type: IntersectionObserver | null

isLoadingPage

Type: boolean

loadedItems

Type: unknown[]

hasMoreData

Type: boolean

effectiveListHeight

Type: string

loadError

Type: string

items

items has a type of unknown[].

Items to render when the repeater is used without cursor paging. If fetchPage is set, the repeater manages its own loaded item collection internally.

renderItem

renderItem has a type of RepeaterRenderItem<unknown> | null.

Callback used to render each repeated item. This is the recommended API for rich custom-element content because the repeater virtualizes items and instantiates them on demand.

layout

layout has a type of "list" | "grid".

Visual layout mode for the rendered content.

Use grid to opt into responsive card-style rows while preserving virtualization and paging behavior.

scrollModel

scrollModel has a type of "contained" | "page".

Scroll behavior model for the repeater viewport.

Use contained for the current nested scrolling behavior driven by list-height. Use page when the repeater should scroll with the document/page instead.

gridColumns

gridColumns has a type of number.

Fixed grid column count fallback used when layout="grid" and no --esp-repeater-grid-columns custom property override is applied.

ariaLabel

ariaLabel has a type of string | null.

Accessible label forwarded to the internal virtualized list.

listHeight

listHeight has a type of string.

The height of the repeater viewport. Accepts any valid CSS height value. Defaults to 60vh. Ignored when scroll-model="page".

pageSize

pageSize has a type of number.

Number of items requested per page when fetchPage is used.

prefetchThreshold

prefetchThreshold has a type of number.

Number of items from the end of the currently loaded set at which the repeater should prefetch the next page.

loading

loading has a type of boolean.

External loading flag for non-paged usage or for cases where the consumer wants to force a loading state.

loadingMessage

loadingMessage has a type of string.

Default loading message used when no custom loading or skeleton slot content is provided.

emptyMessage

emptyMessage has a type of string.

Default empty-state message used when no custom empty slot content is provided.

errorMessage

errorMessage has a type of string.

Optional consumer-provided error message. When set it takes priority over internal fetch errors for display purposes.

fetchPage

fetchPage has a type of | ((params: CursorPageRequest) => Promise<CursorPageResult<unknown>>) | null.

Provide a callback to enable cursor-based infinite paging. When set, the repeater fetches additional items as the user scrolls near the end of the currently loaded range.

fetchPageBacker

Type: | ((params: CursorPageRequest) => Promise<CursorPageResult<unknown>>) | null

isPagedMode

Type: boolean

isGridLayout

Type: boolean

isPageScrollModel

Type: boolean

isContainedScrollModel

Type: boolean

renderedItems

Type: unknown[]

virtualizerItems

Type: Array<unknown | RepeaterGridRow<unknown>>

isBusy

Type: boolean

activeErrorMessage

Type: string

normalizedPageSize

Type: number

normalizedPrefetchThreshold

Type: number

normalizedGridColumns

Type: number

effectiveGridColumns

Type: number

renderVirtualItem

Type: RenderItemFunction<unknown>

renderVirtualRow

Type: RenderItemFunction<RepeaterGridRow<unknown>>

renderGridVirtualItem

Type: RenderItemFunction<unknown>

seedColorBacker

Type: string

espRoot

Type: EspalierRoot | null

contextBacker

Type: string

scopedTokenOriginalValues

warnedUnknownContexts

pendingInitialThemeRoot

Type: EspalierRoot | null

rootEventSubscriptionsActive

Type: boolean

subscribedRoot

Type: EspalierRoot | null

rootEventUnsubscribers

Type: Array<() => void>

intentBacker

Type: EspalierIntentVariant

intentEmitsTokens

intentEmitsTokens has a type of boolean.

Whether a non-neutral intent emits its inline tokens (--esp-color-primary and the filled-action pair). Interactive controls need them; chrome whose intent treatment is class-based (badges, callouts, status pills — see intentSurfaceTokens) opts out so a decorative intent never rewrites inherited tokens for slotted content.

warnedUnknownIntents

seedColor

Type: string

correlationId

scheme

scheme has a type of "dark" | "light".

The scheme to use for the component. This property is used internally to control the light/dark scheme so it matches the scheme of esp-root. It should not be set manually, it exists as an attribute for styling purposes.

intent

intent has a type of EspalierIntentVariant.

The element's intent — its meaning: neutral (no pin), or success, warning, danger, info — each pinned to its fixed status family (blue for info), retunable per theme via intents. On token-emitting controls a non-neutral intent pins the filled-action pair to that family, derived over the governing zone's theme; class-styled chrome (badges, callouts, status pills) opts out of inline emission and renders its treatment from CSS classes instead. An intent never repaints the surrounding zone, which is what contexts are for. Removing the attribute restores the element's own default intent.

context

context has a type of string.

A theme-defined color zone. The selected context rebinds designer-facing roles and emits a complete, contrast-enforced semantic token table on this host for descendants to inherit.

handleSeedColorChanged

handleSchemeChanged

handleThemeChanged

handleIconSpriteUrlChanged

intentColorSources

intentColorSources has a type of `Readonly< Record<EspalierIntentVariant, ColorSource | "">

`.

Intent color sources: the meaning-bearing families an intent pins the filled-action pair to. neutral pins nothing; each other intent maps to its own fixed status family (ESP0172 gave info a real blue family, replacing the complementary borrow the retired variant system used), and a theme's intents field retunes the family colors themselves.

semanticActionTokens

semanticActionTokens has a type of ReadonlySet<SemanticColorName>.

Semantic tokens that paint a control's filled action surface — the pair an intent recolors. Everything else inherits the zone cascade, which is the ESP0166 fix: under the SHY fitted theme the retired variant re-seeding painted a danger callout's background mint green; an intent leaves the zone's surfaces alone and pins only the action pair (plus --esp-color-primary for state derivations) to the intent's own status family — fixed hues by default, retunable per theme via intents. Task 098's guarantee survives structurally: the pin is by source, so no theme mapping can rotate a destructive / warning / positive action off its semantic hue.

Methods

<esp-repeater> has the following methods:

clear

Clear the currently rendered items. In cursor-paged mode this also clears the cursor and any pending load error.

reload

Clear any loaded pages and request the first page again when cursor paging is enabled.

scrollToIndex

Delegate scrolling to the underlying virtualizer.

traverseToClosest

Traverse up the DOM tree to find the closest element that matches the selector. This method is aware of shadow DOM boundaries and will traverse through them to find the element.

Slots

<esp-repeater> has the following slots:

empty

Optional empty-state content shown when the repeater has no items.

error

Optional error-state content shown when loading fails or errorMessage is set.

loading

Optional loading-state footer shown while additional pages are loading.

skeleton

Optional initial loading state shown when loading starts before any items are rendered.

CSS Properties

<esp-repeater> has the following CSS properties:

--esp-repeater-background

Background of the repeater container.

--esp-repeater-border

Border of the repeater container.

--esp-repeater-border-radius

Border radius of the repeater container.

--esp-repeater-gap

Space between repeated items.

--esp-repeater-padding

Padding used by repeater state panels and the loading/error footer.

--esp-repeater-content-padding

Padding inside the virtualized content region. Defaults to 0.

--esp-repeater-grid-columns

Grid column count when layout="grid". Supports media-query overrides.

--esp-repeater-grid-column-gap

Horizontal gap between grid columns.

--esp-repeater-grid-row-gap

Vertical gap between grid rows.

--esp-field-background

Background color of the shared field shell. Defaults to var(--esp-color-layer-2).

--esp-field-border-color

Border color of the shared field shell. Defaults to var(--esp-color-border).

--esp-field-border-width

Border width of the shared field shell. Defaults to 1px.

--esp-field-text-color

Text color used inside the shared field shell. Defaults to var(--esp-color-text).

--esp-field-hover-bg

Hover background color of the shared field shell. Derived from --esp-field-background.

--esp-field-focus-bg

Focus background color of the shared field shell. Derived from --esp-field-background.

--esp-field-focus-shadow

Shadow color used for shared field focus treatment. Defaults to var(--esp-color-shadow).

Components API Guides Getting started Styling Espalier Browser support GitHub npm package Taproot I/O