@guidelytech/guide-runtime
v0.8.0
Published
Guidely browser runtime: selectors, positioning, overlays and step rendering
Maintainers
Readme
@guidelytech/guide-runtime
Framework-free DOM engine used by the Guidely SDK and the dashboard editor: element resolution, Shadow-DOM host and theming, step renderers (floating-ui positioning), the guide controller, checklist / survey / resource-center widgets, an allowlist HTML sanitizer and the authoring picker.
pnpm add @guidelytech/guide-runtimeimport { runGuide } from "@guidelytech/guide-runtime";
const controller = runGuide(publishedGuide, {
theme: config.theme,
ctx: () => targetingContext,
onEvent: (e) => console.log(e.name, e.stepId),
onNavigate: (url) => router.push(url),
});
controller.start();Selectors
| Export | Description |
|---|---|
| resolveTarget(target \| selectors, root?) | Tries strategies in order (id, data-attr, aria, css, text, xpath); a strategy wins only when it matches exactly one visible element. |
| waitForTarget(target, { timeoutMs, signal, root, pollMs }) | MutationObserver + ≤250ms polling; rejects with TargetTimeoutError / AbortError. timeoutMs: 0 waits forever. |
| generateSelectors(el) | Robust-first strategies for the picker: stable id (generated ids like :r1:, radix-…, long digit runs are skipped), data-testid/data-tour/data-*, aria-label, name/role, short unique CSS path (nth-of-type only when needed), text fallback for buttons/links/headings. |
| describeElement(el) | { selectors, textSnapshot, rect, tag }. |
| textSnapshotOf(el), isVisible(el), isStableId(id), isGuidelyElement(el), querySelectorStrategy(strategy, root), normalizeText(text), urlMatches(pattern, url) | Helpers. |
Host and theme
ensureHost() appends a single <div id="guidely-root"> with an open shadow root containing all
styles (:host{all:initial}) and a polite live region. createScope(theme, appearance) creates a
themed container (--g-primary, --g-bg, --g-text, --g-radius, --g-font, --g-z,
--g-overlay; data-theme="light|dark", data-anim). auto follows prefers-color-scheme;
prefers-reduced-motion disables animations. resolveTheme, applyTheme, destroyHost,
DEFAULT_THEME, HOST_ID, STYLES are also exported.
Rendering
renderStep({ scope, step, index, total, target, asModal, onButton, onClose, onOpen }) renders any
step type and returns { el, card, destroy }:
modal— centered card, optional overlay,role="dialog" aria-modal, Tab focus trap.tooltip/popover— anchored with floating-ui (offset,flip/autoPlacement,shift,arrow,autoUpdate),role="tooltip",aria-describedbyset on the target.spotlight— four-rect overlay with a cut-out around the target (target stays clickable) + ring + anchored card.hotspot— pulsing dot at the target's corner, opens the card on click or hover.banner— fixed top/bottom bar,role="status".slideout— corner card.custom— sanitizedcustomHtmlonly; elements withdata-g-action="next|back|dismiss|complete|skip"act as buttons.
Chrome: close button (Escape when showClose), image, title, sanitized body, progress
("2 of 4"), buttons with variants, focus moved into the card and restored on close, screen-reader
announcements, cards clamped to 100vw - 32px, ≥40px touch targets.
anchor(reference, floating, options) and trackRect(el, cb) expose the positioning primitives.
Controller
runGuide(guide, options): GuideController — options: theme, ctx, onEvent, onNavigate,
onAction (start_guide / event / open_resource_center), onError, onEnd, eventBus
(for advanceOn: "event"), startAtStep, currentUrl, container, doc.
Controller: start(), next(), back(), goTo(stepId), dismiss(), complete(), skip(),
resume() (re-check a step waiting for its URL), destroy(), getState().
Handles advanceOn (button, element_click, element_visible, event, delay, any),
branches (evaluateRules(branch.when, ctx) when leaving a step), step-level targeting, multi-page
steps (step.url), target waits with skip / show_as_modal / end_guide / wait fallbacks,
and emits guide_viewed, guide_started, step_viewed, step_completed, guide_completed,
guide_skipped, guide_dismissed. Rendering is wrapped in try/catch and reported via onError.
Widgets
renderChecklist({ scope, config, progress, open, onTaskClick, onDismiss, onOpen, onClose })→{ open, close, toggle, isOpen, setProgress, destroy };isChecklistComplete(config, progress).renderSurvey({ scope, config, title, onSubmit, onDismiss, onChange })→{ getAnswers, showThankYou, destroy };isQuestionVisible(question, answers)evaluatesshowWhen.renderResourceCenter({ scope, config, guides, search, onStartGuide, onOpenChecklist, onArticleView, onOpen, onClose, hideLauncher })→{ open, close, toggle, isOpen, destroy }.
Sanitizer
sanitizeHtml(html), sanitizeToFragment(html), setSanitizedHtml(el, html) — allowlist of
p br strong b em i u a ul ol li img h1-h4 code pre blockquote span div hr button, attributes
href src alt title target rel class (+ data-g-action/data-g-value), drops
script/style/iframe/object/embed/form/input, on* handlers, javascript:/data: URLs (except
data:image/* on img), forces rel="noopener noreferrer" on target="_blank".
Authoring
startAuthoring({ onPick, onExit, dashboardOrigin, message })→{ setStatus, setPicking, stop }— toolbar, hover outline, capture-phase click-to-pick callingonPick({ selectors, textSnapshot, rect, url, element }).previewStep(step, theme, { appearance, onEnd })→{ controller, destroy }.highlightSelectors(selectors, { durationMs })→{ counts, resolved, destroy }.
