Skip to content
Documentation navigation

@rightxt/tracker-core

npm version TypeScript declarations

The shared RXT Tracker runtime for frontend developers building a custom integration. Core queries source elements, measures scroll geometry, groups markers into clusters, handles semantic interaction, and coordinates updates. Your integration owns how that state becomes visual output.

Use Core when writing a renderer or binding projected views to your application's DOM. Applications using an official adapter can start with that package's documentation; Core is not a prerequisite.

Installation, entry points and debug builds

pnpm add @rightxt/tracker-core

Core provides public ESM entry points and TypeScript declarations:

Normal semantic entry Explicit debug entry Purpose
@rightxt/tracker-core @rightxt/tracker-core/debug Shared configuration/rule helpers, constants, types, and error classes.
@rightxt/tracker-core/projection @rightxt/tracker-core/projection/debug Projection integration factory and immutable rendering views.
@rightxt/tracker-core/renderer @rightxt/tracker-core/renderer/debug Direct Renderer factory, renderer protocol, records, and presentation helpers.
@rightxt/tracker-core/advanced @rightxt/tracker-core/advanced/debug Debug trace retrieval for supported Core facades.

Neutral JavaScript entries use package conditions: development selects debug behavior; production/default resolution selects production behavior. Explicit /debug entries bypass that choice. Static exports and declarations match within each normal/debug family, while debug runtime instrumentation differs. This is Core's package model, not a promise that every Tracker package has the same artifacts.

@rightxt/tracker-core/style.css exports the canonical stylesheet, and @rightxt/tracker-core/package.json exposes package metadata. JavaScript does not inject CSS. In a browser application whose bundler supports CSS imports:

import '@rightxt/tracker-core/style.css';

Choose Projection or Direct Renderer

Decision Projection Direct Renderer
Best fit Application/framework owns DOM and consumes immutable view state. Your renderer implements synchronous visual-output hooks.
Factory createTrackerProjectionIntegration(configuration?) createTrackerRendererIntegration(configuration, { renderer })
Rendering Read getProjection() and subscribe with subscribeProjection(). Implement the render hooks needed by your UI.
Mount input Exact renderRoot: HTMLElement. rendererTarget, discriminated as host or exact root.
Configuration Complete replaceConfiguration({ options, rules }). Complete replacement plus options/rule-specific mutations.
Additional capabilities Preflight, adapter coordination, and flushRender() for pending work. Root/options/rules reads and keyed activateItem().

Both facades provide lifecycle, Core events, manual synchronization, snapshots, and stats. They do not have identical method sets. See the custom integration guide for the workflow and the rendering reference for exact protocols.

Quick starts

These independent browser examples run after a connected <article> containing headings exists. They use page scrolling; the application chooses the output location. Call the returned cleanup function when the owning view is removed.

Projection: bind a rail to DOM

This binding owns its output nodes, applies projected presentation, and preserves keyed items. Core supplies interaction and geometry; the binding supplies DOM reconciliation.

import { createTrackerProjectionIntegration } from '@rightxt/tracker-core/projection';
import '@rightxt/tracker-core/style.css';

function mountProjection(sourceRoot) {
  const document = sourceRoot.ownerDocument;
  const root = document.createElement('div');
  const layer = document.createElement('div');
  const viewport = document.createElement('div');
  root.append(layer, viewport);
  document.body.append(root);

  const previousViews = new WeakMap();
  const items = new Map();
  const integration = createTrackerProjectionIntegration({
    options: { placement: 'right', a11y: { enabled: true, keyboard: true } },
    rules: [{ selector: 'h2', label: (element) => element.textContent }],
  });

  function applyView(node, view) {
    const previous = previousViews.get(node);
    for (const name of Object.keys(previous?.attributes ?? {})) {
      if (!(name in view.attributes)) node.removeAttribute(name);
    }
    for (const name of Object.keys(previous?.styleVars ?? {})) {
      if (!(name in view.styleVars)) node.style.removeProperty(name);
    }
    node.className = view.className;
    for (const [name, value] of Object.entries(view.attributes)) node.setAttribute(name, value);
    for (const [name, value] of Object.entries(view.styleVars)) node.style.setProperty(name, value);
    previousViews.set(node, view);
  }

  function renderView(state) {
    applyView(root, state.chrome.root);
    applyView(layer, state.chrome.markersLayer);
    layer.hidden = state.chrome.markersLayer.hidden;
    applyView(viewport, state.viewport);
    viewport.hidden = state.viewport.hidden;
    const currentKeys = new Set(state.items.map((item) => item.key));
    for (const [key, node] of items) {
      if (!currentKeys.has(key)) {
        node.remove();
        items.delete(key);
      }
    }
    for (const item of state.items) {
      const node = items.get(item.key) ?? document.createElement('div');
      applyView(node, item);
      node.setAttribute('data-rxtt-key', item.key);
      if (item.key === state.selection.selectedKey) node.setAttribute('data-rxtt-selected', 'true');
      else node.removeAttribute('data-rxtt-selected');
      items.set(item.key, node);
      layer.append(node);
    }
  }

  renderView(integration.getProjection());
  const unsubscribe = integration.subscribeProjection(({ state }) => renderView(state));
  function cleanup() {
    try {
      integration.destroy();
    } finally {
      unsubscribe();
      items.clear();
      root.remove();
    }
  }
  try {
    integration.mount({ renderRoot: root, sourceRoot });
  } catch (error) {
    cleanup();
    throw error;
  }
  return cleanup;
}

const stopTracker = mountProjection(document.querySelector('article'));
// Call stopTracker() when the application removes this view.

Only attributes/styles previously applied by this binding are removed during reconciliation. The root identity stays fixed for the mount. Larger bindings can use changed Projection domains to limit DOM work; the Projection protocol explains coherent commits and listener recovery.

Direct Renderer: custom marker navigation

This renderer presents measured markers as native navigation buttons, with clustering and the viewport indicator disabled. It owns hit testing and forwards marker keys through activateItem(). The custom list uses native button styling; a renderer implementing the standard rail should also import @rightxt/tracker-core/style.css and apply the standard presentation contract.

import { createTrackerRendererIntegration, getPrimaryMarkerRecord } from '@rightxt/tracker-core/renderer';

function mountMarkerList(sourceRoot, host) {
  let root = null;
  const renderer = {
    mount({ target, document }) {
      root = document.createElement('nav');
      root.setAttribute('aria-label', 'Content sections');
      target.host.append(root);
      return root;
    },
    renderMarkers(records) {
      const buttons = records.map((record) => {
        const key = record.key;
        const marker = getPrimaryMarkerRecord(record);
        const button = root.ownerDocument.createElement('button');
        button.type = 'button';
        button.textContent = marker.label || marker.selector;
        button.onclick = (sourceEvent) => {
          sourceEvent.stopPropagation();
          integration.activateItem(key, { sourceEvent });
        };
        return button;
      });
      root.replaceChildren(...buttons);
    },
    unmount() {
      root?.remove();
      root = null;
    },
  };
  const integration = createTrackerRendererIntegration(
    {
      options: { viewport: { enabled: false }, clustering: { enabled: false } },
      rules: [{ selector: 'h2', label: (element) => element.textContent }],
    },
    { renderer },
  );

  try {
    integration.mount({ rendererTarget: { kind: 'host', host }, sourceRoot });
  } catch (error) {
    integration.destroy();
    throw error;
  }
  return () => integration.destroy();
}

const host = document.createElement('div');
document.body.append(host);
const stopTracker = mountMarkerList(document.querySelector('article'), host);
// On view removal: stopTracker(); host.remove();

The host is caller-owned; the returned strict descendant is renderer-owned. The button handler stops propagation before forwarding activation, so the same click is not also delivered to root-level track handling. This minimal renderer uses fixed presentation; a configurable rail additionally implements track, marker-presentation, viewport, and selection hooks as needed. Hooks are synchronous, and a Promise is not a valid mount root. The renderer reference defines inputs, ownership, and failure behavior.

Core concepts

Concept Meaning
Tracker One integration coordinating the represented content, rendering, interaction, and lifecycle.
Track The visual rail along the represented physical axis; one part of a Tracker.
Viewport The currently visible portion of the represented scroll area.
Viewport indicator The visual item showing that viewport on the track. Disabling it does not disable observation.
Marker A representation of a matched source element and its rule behavior.
Cluster A spatial group rendered as one item, with a primary marker.
Rule An ordered selector plus label, presentation, scroll, and focus behavior.
Source root The scope queried for source elements.
Scroll root The authoritative page/window or element whose scrolling is represented.
Render root / renderer target The actual output HTMLElement, or Direct Renderer's host/root ownership request. It also selects the active realm.

Configuration has separate options and rules channels. Options control the integration; rules select and describe source elements. The source scope and scroll context can differ subject to their environment constraints.

Configuration reference

Creation accepts { options?, rules? }; both default to empty input resolved against defaults. All option fields are optional. The grouped tables below cover all 36 configurable leaves. Containers such as updates.mutation.options are not additional leaf values.

Track geometry and placement

Option Type / values Default Meaning and constraints
orientation 'vertical' | 'horizontal' 'vertical' Physical Y or X axis. Changing orientation while mounted in element mode revalidates that scroll root for the requested axis and can reject before commit.
placement 'left' | 'right' | 'top' | 'bottom' Vertical: 'left'; horizontal: 'top' Vertical accepts left/right; horizontal accepts top/bottom. An explicitly incompatible pair rejects. An omitted/inherited incompatible placement falls back to the new axis default. No scrollbar-side inference.

Presentation

Option Type / values Default Meaning and constraints
cssVariables Plain map of string or null values {} Root custom-property input. Supported Tracker names and valid application names are accepted; renderer geometry/unknown --rxtt-* names reject. Strings remain unchanged in committed reads; null deletes a configured entry in a patch. Replacement removes omitted entries. See Styling for output normalization.
track.className string '' Application classes appended to the standard .rxtt root. Whitespace normalized and tokens deduplicated; reserved Tracker service classes reject.
viewport.enabled boolean true Show the viewport indicator when geometry is available. Does not enable/disable update sources.
viewport.className string '' Application classes on .rxtt__viewport; same class normalization/reservation rules.
markerLayer.className string '' Application classes on .rxtt__markers; same class rules.
marker.attributes Plain map: string, finite number, boolean, or null {} Global application attributes for marker/cluster items. Names lowercased; collisions/reserved names reject. Global patch null deletes an entry; rule null suppresses inheritance. See the name constraints below.
marker.className string '' Application classes for every marker/cluster, combined with its owning rule's classes. Same class rules.
marker.title boolean true Use a nonempty resolved label as native title; an explicit rule boolean overrides the global policy.

Application attributes support role, supported data-*, and supported aria-* names. role requires a nonempty trimmed string; other supported non-null values serialize to strings. class, style, id, tabindex, title, event-handler/framework-special names, and data-rxtt-* are reserved. Use the dedicated class/title/CSS options. Global and per-rule presentation composition is defined in the rule guide.

Clustering

Option Type / values Default Meaning and constraints
clustering.enabled boolean true Group nearby measured markers; false keeps individual marker records.
clustering.threshold Finite number >= 0 2 Distance in track percentage points, not pixels/CSS length. Grouping compares against accumulated cluster bounds. The first spatial member is primary and supplies cluster presentation/activation behavior.

Automatic updates

Each family is independently enabled. Delays/debounces use milliseconds. Observer target callbacks are synchronous functions returning arrays; a bare array is not the configuration type.

Option Type / values Default Meaning and constraints
updates.mutation.enabled boolean true Connect the MutationObserver source for relevant external source changes.
updates.mutation.targets (context) => Node[] Resolver returning [sourceRoot] Select mutation targets in the active document. Invalid/foreign/Tracker output targets are filtered. A throw/non-array result falls back to defaults; explicit [] leaves this observer disconnected.
updates.mutation.debounce Finite number >= 0 100 Debounce relevant mutation batches before requesting marker synchronization.
updates.resize.enabled boolean true Control both ResizeObserver and active Window resize updates.
updates.resize.targets (context) => Element[] Source Element or ShadowRoot host, element scroll root when applicable, and render root; deduplicated Configure ResizeObserver only; Window resize is independent of this target list. Throw/non-array falls back to defaults; [] disconnects ResizeObserver, not Window resize.
updates.resize.debounce Finite number >= 0 50 Shared debounce for ResizeObserver and Window resize signals.
updates.scroll.enabled boolean true Frame-coalesced scroll invalidation, including marker geometry and viewport synchronization. False stops automatic viewport synchronization as well.
updates.interval.enabled boolean false Enable polling independently of the other update sources.
updates.interval.delay Finite number > 0 1000 Polling period while interval updates are active.

Target context contains observerType, sourceRoot, scrollRoot, scrollMode, renderRoot, document, window, defaultTargets, and reason. reason describes connection/reconnection; defaultTargets supplies fresh runtime defaults. Results are deduplicated. Mutation accepts Nodes; resize requires Elements and allows the integration's own render root. Callbacks may inspect the active DOM but must return synchronously and must not mutate the same Tracker during resolution. See observation targets.

The seven native mutation controls are separate configurable leaves:

Option Type / values Default Meaning and constraints
updates.mutation.options.childList boolean true Observe added/removed children. At least one effective category must remain enabled.
updates.mutation.options.subtree boolean true Extend observation to descendants; this alone is not an observation category.
updates.mutation.options.attributes boolean false Observe attributes. Effective native value becomes true when an attribute filter exists or old values are requested, even if this field is false.
updates.mutation.options.attributeFilter Nonempty, non-sparse array of nonempty strings Omitted Restrict observed attribute names and enable effective attribute observation.
updates.mutation.options.attributeOldValue boolean Omitted Request old attribute values when true; also enables effective attribute observation.
updates.mutation.options.characterData boolean false Observe text data. Effective native value becomes true when character-data old values are requested.
updates.mutation.options.characterDataOldValue boolean Omitted Request old text-data values when true and enable effective character-data observation.

The effective configuration must enable child-list, attributes, or character data. An all-disabled effective configuration rejects; turn off updates.mutation.enabled to disable the source instead.

Interaction

Option Type / values Default Meaning and constraints
interaction.activation boolean true Enable marker, cluster, discrete track, and selected-item keyboard activation. False suppresses their semantic action/activation notifications.
interaction.drag boolean false Enable continuous track dragging independently of activation. Standard root data-rxtt-drag="true" denotes enabled capability, not a current drag session.

Accessibility

Option Type / values Default Meaning and constraints
a11y.enabled boolean false Standard root gets an accessible label when enabled, or aria-hidden="true" when disabled.
a11y.keyboard boolean false Enable arrows/Home/End selection and Enter/Space activation when a11y is also enabled. enabled: false, keyboard: true rejects.
a11y.label Nonempty string 'Content tracker' Root accessible label when enabled. Use a meaningful name for the represented content.

Patch validation includes inherited values: disabling a11y.enabled while an inherited a11y.keyboard remains true rejects. Change both together when disabling keyboard accessibility. Logical selection is separate from browser focus; preserve visible focus and selected-item styling in custom output.

Diagnostics

Option Type / values Default Meaning and constraints
diagnostics.warnings boolean true Gate fallback console.warn only; configured output.warn, warning stats, and the warning event remain active.
diagnostics.metrics boolean false Collect render timing when a clock is available. Counters update independently of this flag.
diagnostics.output Sink object with optional warn/error functions, or null Omitted; no custom sink Replace console fallback per implemented severity. Null clears the sink. It is caller-owned and callbacks are best-effort; see Diagnostics and errors.

Configuration changes and validation

Normal construction and configuration/rule mutations are strict and atomic: any validation diagnostic, including a warning, rejects the candidate without a partial commit. Unknown keys, invalid values, and duplicate selectors reject. A known own property set to undefined is invalid; omission is different. Null is accepted only where the field permits it.

Operation Facade Behavior
replaceConfiguration({ options, rules }, params?) Both Replace both channels atomically; both own fields are required. Omitted option leaves resolve from defaults.
replaceOptions(options, params?) Direct Renderer Replace options from defaults and preserve separate rules.
patchOptions(options, params?) Direct Renderer Deep patch from committed options; omitted fields remain, with field-specific null deletion.
replaceRules(rules, params?) Direct Renderer Replace the complete ordered list.
addRule(rule, params?), removeRuleByIndex(index, params?), removeRuleBySelector(selector, params?) Direct Renderer Incremental rule changes; addRule supports an insertion params.index. Selectors are normalized and indices validated.

Optional params.render defaults to true. render: false leaves required work dirty for later synchronization. Alive unmounted integrations accept configuration changes; mounted ones normally schedule required work. Projection exposes complete replacement rather than options/rule-specific mutators, so keep the desired envelope in application state.

Pure validateOptions(), validateRule(), and validateRules() are non-committing tooling helpers returning candidates and diagnostic arrays. Recovered output is not a normal partial mutation. The Core API reference owns exact recovery, helper, and failure contracts.

Rules reference

Rules are processed in priority order. selector is required, trimmed, nonempty, and unique after normalization. The first matching rule owns an overlapping source element. Selector queries follow the source scope; DOM-dependent syntax is validated against the actual source at mount/mounted update boundaries.

The tables cover all 12 rule leaves. marker, scroll, and focus are containers; scroll and focus also accept boolean shorthands.

Selection, labels, and presentation

Field Type / values Default Meaning and constraints
selector Nonempty CSS selector string Required Trimmed unique selector; rule order determines overlapping element ownership.
label String, null, or (element) => string | null null Static or synchronous source-Element label. Throw is diagnosed; non-string callback output gives no label. Promises are not awaited. Nonempty labels can supply native title.
marker.className string '' Normalized application classes combined with global marker classes. Reserved service classes reject.
marker.title boolean Inherit global policy Explicit true/false overrides global marker.title; title still needs a nonempty label. Omit to inherit, rather than supplying own undefined.
marker.attributes Plain map: string, finite number, boolean, or null {} Same supported names/serialization as global attributes. Rule values override globals; rule null persistently suppresses the matching inherited attribute.
marker.cssVariables Plain string map {} Complete item map, not a patch. Accepts 17 marker/cluster Tracker variables and valid application custom properties; null rejects. Inline item values override inherited values; strings may be blank.

For a cluster, the primary spatial marker supplies rule presentation. Global/rule classes combine, attributes override or suppress, and rule title policy overrides the global flag. See rules and marker behavior.

Scroll and focus

Field Type / values Default Meaning and constraints
scroll.enabled boolean true Attempt scrolling during accepted activation, before focus. scroll: false disables just this phase.
scroll.target 'self', nonempty selector, or (element) => Element | null 'self' Resolve the navigation target synchronously. It must belong to the active document and, in element mode, the authoritative scroll subtree.
scroll.behavior 'auto' | 'smooth' 'auto' Requested scrolling behavior.
scroll.align 'start' | 'center' | 'end' | 'nearest' 'start' Alignment along the represented physical axis.
focus.enabled boolean false Attempt focus after scrolling. focus: true enables it with the default target.
focus.target Same target forms as scroll.target 'self' Same realm/subtree constraints; final target must be an HTMLElement.

Boolean scroll/focus shorthands toggle their enabled value while retaining other defaults. Target selectors search source descendants, then the containing ShadowRoot when present, then the owner document. Invalid targets, selector failures, or throwing target callbacks yield no usable target for that phase and diagnostics. Callbacks must return synchronously and must not mutate the same Tracker while resolving.

Strict normal mutations reject diagnostic-bearing rules. Pure rule validation removes invalid rule-marker CSS names/entries from its recovered candidate, keeps valid entries, and reports diagnostics. This sanitation does not allow a normal mutation to silently accept only the valid portion. Validation depth and activation behavior provide the detailed contracts.

Mounting and roots

Mount after the supplied roots/host are connected. Projection takes:

integration.mount({ renderRoot, sourceRoot, scrollRoot });

Direct Renderer instead takes one ownership target:

integration.mount({ rendererTarget: { kind: 'host', host }, sourceRoot, scrollRoot });
// Or: rendererTarget: { kind: 'root', root }

sourceRoot and scrollRoot are optional in both shapes; omit their properties to use defaults. The Projection root or Direct Renderer target selects the active Document/Window, and the other roots must be valid in that realm.

  • Source roots can be Document, Element, or a directly supplied open ShadowRoot. Queries do not automatically enter nested shadow trees or iframe documents. Element sources match descendants, not themselves.
  • Omitted scroll root, the active Window, and active-document body/documentElement/scrollingElement aliases select window mode. An omitted source then uses that document's body.
  • A supported other HTMLElement selects element mode; its client/scroll geometry is represented and the omitted source defaults to that element. Element mode requires the supported CSS/geometry profile, not just any scrollable node.
  • Source, scroll, and output cannot mix documents. For same-origin iframes use current child-document identities and unmount before remounting after navigation. A ShadowRoot source does not relocate output or install CSS there.

Projection owns no application root removal. A Direct Renderer exact-root mount must return that exact root; a host mount must return a connected strict HTMLElement descendant of the host. Actual roots must satisfy source isolation, same-realm validity, unique active registration, and fixed mount-generation identity. Core may remove abandoned renderer-owned host output as cleanup fallback, while caller-owned roots remain externally owned.

See environments for defaults, container profiles, shadow scopes, and navigation, and root ownership for the renderer contract.

Lifecycle

Creation commits initial options/rules and starts unmounted. A successful mount() establishes one active generation and commits mounted state after required setup and initial synchronization. A second mount while mounted rejects: unmount before changing context identities.

unmount() is reversible and effectively idempotent at the public lifecycle boundary. It releases active runtime context, pending generation work, observers/listeners, and renderer mount resources. The same integration, configuration, and ordered rules survive; it can mount again with valid current roots. Renderer-owned output follows its cleanup protocol; application-owned output stays under application control.

destroy() commits destroyed state, is terminal and idempotent, and permits no remount. Failed mount rolls back to valid unmounted state. Cleanup can throw after unmounted/destroyed settlement; an exception does not make a destroyed integration reusable.

Method Normal use
getState() Read 'unmounted', 'mounted', or 'destroyed'.
isMounted() / isDestroyed() Query committed lifecycle state.
whenDestroyed() Get the integration's shared completion Promise; resolves on terminal destroy even if cleanup reports failure.

Manual rendering requires mounted state. Configuration changes and stats reset require an alive integration. Lifecycle/snapshot/stats reads remain available after destroy; Direct Renderer options/rules reads reject there. For complete capability and cleanup settlement rules, see Core lifecycle.

Events

Both facades expose on(name, handler) and off(name, handler). on() returns an idempotent unsubscribe for that registration. Registering the same handler identity twice delivers once per event but creates two ownership registrations; one unsubscribe releases only its owner. off() removes all current registrations for that pair.

Event When Primary payload meaning
marker:activate After accepted marker scroll/focus attempts. Marker key, source Element, owning rule/selector, label, nullable source Event.
cluster:activate After primary-marker activation attempts. Cluster key/count, member and primary-marker descriptors, nullable source Event.
track:activate After discrete track activation; drag movement is excluded. Nullable track percentage position and source Event.
selection:change A committed logical selected-key transition. Previous and selected keys, each nullable; selection is distinct from browser focus.
sync:start A Core synchronization starts; initial mount notifications are staged. Reason, scheduled flag, nullable timing.
sync:end Successful Core synchronization. Marker/cluster counts and nullable duration/timestamp.
warning After warning stats and output. Stable diagnostic code, human message, contextual details.
destroy After terminal state/cleanup attempts, before subscription teardown. Empty payload.

Delivery is synchronous. Activation behavior occurs before notification, and listener return values cannot cancel it. sync:end confirms successful Core synchronization, not browser paint or a framework DOM commit. There is no generic Core error, mount, or unmount event.

Core contains handler throws and observes rejected returned thenables without rolling back the emitting operation. State-changing calls during public event/snapshot dispatch defer until the boundary exits; renderer/lifecycle callbacks have different transition restrictions. New on() subscriptions reject after destroy; off() then returns false. The event reference owns exact payloads, ordering, and failure semantics.

Synchronization and automatic updates

render() performs full synchronization immediately through the scheduler/flush path. requestRender() schedules and coalesces full synchronization. Both require mounted state and take no target argument. Core has no public refresh() method. Projection additionally exposes flushRender(), which only drains already-pending work and does not request new work.

The four update families are mutation, resize, scroll, and interval. Mutation reacts to relevant external DOM changes, excluding Tracker renderer feedback. Resize combines ResizeObserver and Window resize; updates.resize.targets configures only ResizeObserver. Scroll updates include marker geometry and viewport synchronization, not just a viewport-only write. Interval polls independently.

Automatic observation cannot detect every visual change. CSS/CSSOM-only updates, external stylesheets, and application layout changes outside observed signals may need requestRender() or render(). If the application owns all invalidation, disable each family separately and schedule explicitly. A framework render by itself is not a Core invalidation API.

See updates and refresh for target selection, coalescing, manual synchronization, and geometry recovery.

Styling

For output implementing the standard rail, import/use @rightxt/tracker-core/style.css. Core JavaScript does not inject that stylesheet. Install canonical CSS and application themes in the scope containing the actual .rxtt tree, including its document or user-managed ShadowRoot.

Options and rule presentation add application classes, supported attributes, title policy, and custom-property values. The public styling contract includes 33 root Tracker variables, of which 17 are supported at rule-marker scope, plus service classes and data attributes. Valid application-owned custom properties outside the reserved Tracker namespace are also supported. Keep the required service hooks when implementing standard output.

data-rxtt-drag="true" means drag capability is enabled; it is not a current-dragging flag. Committed root CSS strings remain unchanged in options/read state, including whitespace. Standard Projection root output trims nonblank strings and omits blank/whitespace-only values. A custom Direct Renderer defines its own output handling; do not assume it applies that normalization unless it uses the corresponding helper. Rule/item CSS is a separate scope.

The styling reference defines the complete variable/class/attribute contract. The Theme Builder source entry provides the tool for editing/previewing themes and exporting application overrides; this link opens repository source. Exported overrides supplement canonical CSS. The styling reference remains authoritative for accepted names and semantics.

Snapshots and stats

Both Core facades expose getSnapshot(), subscribeSnapshot(listener), getStats(), and resetStats().

Snapshots are deeply frozen Tracker-owned runtime read graphs with DOM-free marker/cluster records, useful for integration state observation and safe retention. Snapshot subscriptions deliver future publications synchronously, without replaying initial state: read getSnapshot() explicitly. They observe publication/settlement, not every internal write. Projection rendering state and observation snapshots are distinct representations.

getStats() returns a detached, unfrozen clone of counters, diagnostic totals, and last-render data. Counters update independently of diagnostics.metrics; the flag gates timing only. resetStats() is available while alive and clears counters/retained diagnostics/last render without requesting rendering or clearing the rendered records. Reads remain available after destroy.

See runtime state for full structures, snapshot keys and identity, subscription failure behavior, timing, reset, and retained terminal state.

Diagnostics and errors

The root entry exports TrackerError, TrackerConfigurationError, and TrackerLifecycleError. Known Tracker errors expose stable codes; inspect those instead of human message text. Not every thrown value is a TrackerError: native errors, aggregates, and renderer failures can cross public boundaries.

diagnostics.output accepts optional warn(code, message, details?) and error(code, message, details?) methods. Each replaces console fallback only for its severity. The sink stays caller-owned; output: null clears it. Core does not flush/dispose it, awaits no sink Promise, and contains sink throws/rejections.

Warnings update retained stats, call configured output or console fallback, then emit warning. diagnostics.warnings: false gates only fallback console.warn; configured output.warn, warning stats, and the warning event remain active. Errors and console.error are unaffected. There is no generic Core error event.

Runtime diagnostics need not throw, and strict validation rejection does not automatically emit its pure diagnostic arrays through runtime channels. Stats/snapshots retain sanitized diagnostic copies; immediate output/event details may be borrowed live objects. See diagnostic channels and errors for codes, sink ownership, and retention.

Debug and advanced

Use the development condition for neutral Core entries or explicit /debug paths when selecting debug instrumentation deliberately. Debug is more than an unminified artifact: debug-capable integrations can materialize TrackerStats.debug and retain selected execution traces.

getTrackerDebugTrace() from @rightxt/tracker-core/advanced (or /advanced/debug) retrieves trace through a compatible debug accessor and an original debug-capable Core facade. Production or incompatible composition returns null. An adapter handle is not that original Core facade. Exact trace shape, retention, timestamp interpretation, and reset/destroy behavior belong to debug and advanced runtime.

API and integration references

Document Use it for
Custom integration guide End-to-end integration workflow and output ownership.
Environment guide Page/container scrolling, source scope, Shadow DOM, and iframe navigation.
Updates and refresh Observation families, scheduling, and explicit synchronization.
Rules and marker behavior Ownership, presentation composition, activation, selection, and clustering.
Styling reference Complete CSS variables, service hooks, style scopes, and themes.
Core API reference Complete facade methods, tooling helpers, lifecycle capabilities, and events.
Projection and Direct Renderer reference Exact view/renderer protocols, roots, hooks, DTOs, and cleanup.
Runtime, diagnostics, and debug Snapshots, stats, error/diagnostic codes, sinks, and advanced trace.
On this page