Skip to Content
📧 Join the Teacharium waitlist to get access. 

Runtime API

Every component receives an api prop (TeachariumWidgetApi). It is the only way to talk to the lesson: Teacharium provides it in the editor, the player, SCORM packages, LTI and the self-hosted player alike.

Where you’re running

PropertyMeaning
api.isEditingAn author is editing the lesson. Don’t run timers, play media or change variables.
api.isReviewModeA learner is reviewing finished work. Show their answers, disable interaction.
api.playerMode"editing" | "preview" | "playbook" | "player" | "review"
api.stepIdId of the step the component is on

A good default: const interactive = !api.isEditing && !api.isReviewMode;

State that survives navigation

useState resets when the learner leaves a step. Use widget state for anything the learner did:

const [selected, setSelected] = api.hooks.useWidgetState<string | null>("selected", null); const { state, updateState, resetState } = api.hooks.useWidgetStateObject({ attempts: 0, showHint: false, });

It’s restored when the learner comes back to the step, and saved with the session so resumed and reviewed lessons show the same thing.

Variables

Lessons have variables that authors use in text ({{score}}), conditions and expressions.

// Read (re-renders on change). Always pass arrays. const [score, name] = api.hooks.useVariableValues(["score", "name"]); // Write api.updateVariables({ score: 10 }); api.incrementVariable("attempts"); api.decrementVariable("lives", 1); // Create a variable for this component. It's prefixed with the component's // id unless you ask for a lesson-wide one; the full name is returned. const answerVar = api.addVariable("answer", "", "string"); api.addVariable("TotalTime", 0, "number", { scope: "lesson", skipPrefix: true });

Let authors pick variables with a variable field instead of hard-coding names.

Expressions and conditions

const [width, height] = api.hooks.useNumberExpressions([widthExpr, heightExpr], [100, 50]); const [greeting] = api.hooks.useStringExpressions(["Hello {{name}}"]); const { result, hasError } = api.hooks.useConditionEvaluation({ expression: "{{score}} >= 80 and {{attempts}} < 3", });

Pass { escapeHtml: true } as the third argument of useStringExpressions when the result is inserted as HTML.

Scoring: items

A component that learners answer registers as an item. Items feed the player’s Check Answer button and feedback, lesson scores, SCORM and LTI results, and review mode.

const item = api.hooks.useIsItem({ options: { type: "scored", maxScore: 1 } }); function onAnswer(choice: string) { const correct = choice === props.correctChoice; item.updateAttempted(true); item.updateCorrect(correct); item.updateScore(correct ? 1 : 0); item.updateAnswer({ humanReadable: choice, machineReadable: choice }); }

type is "scored" (counts toward the score), "practice" (tracked, not scored) or "instructional". A component with several answerable parts (rows of a matrix) can register each with api.hooks.useIsItemWithId(id, options).

To react to the footer’s Check Answer button, subscribe to checkAnswer:

api.hooks.useLessonEventSubscription("checkAnswer", () => { if (!api.isEditing) setShowFeedback(true); });

Events

Components talk to the player and each other through lesson events. Every event has a params object (pass {} when there are no arguments).

const emit = api.hooks.useLessonEventEmitter(); emit({ type: "setNextButtonStatus", params: { status: "disabled" } }); api.hooks.useLessonEventSubscription("step_started", (event) => { /* … */ });

Events you can emit:

Eventparams
nextStep, previousStep{}
goToStep{ targetStepId }
setVariable{ variableName, value }
updateVariables{ variables: { name: value } }
setNextButtonStatus, setCheckAnswerButtonStatus, setHintButtonStatus{ status: "enabled" | "disabled" | "hidden" }
setNextButtonLabel, setCheckAnswerButtonLabel{ label }
showFeedback{ message, variant: "correct" | "incorrect" | "info" | "hint", autoHideMs? }
hideFeedback, checkAnswer, showHint{}

Events you can listen to include lesson_started, step_started, step_completed, section_completed, variable_changed, checkAnswer, showHint, displayAnswer and setItemStatus, plus custom events other components emit. teacharium dev shows every event in its event log.

The action field and executeActions(api, actions) let authors configure a sequence of these events without code.

Media

Media fields store references, not URLs. Resolve them through the host, which signs URLs in Teacharium and maps them to packaged files in exports:

const { data: imageUrl, isLoading } = api.hooks.useResolvedMediaUrl(props.image); const { hlsStreamUrl, mp4Url, thumbnailUrl } = api.hooks.useResolvedVideoUrls(props.video); const { data: audioUrl } = api.hooks.useResolvedVoiceoverUrl( props.voiceover?.enabled ? props.voiceover.contentHash : undefined, props.voiceover?.voice, );

@teacharium/widget also exports an AudioPlayer component.

Numbers

Floating point makes 0.1 + 0.2 equal 0.30000000000000004. Use the helpers from @teacharium/widget instead of toFixed, === and bare value + step:

import { formatNumber, roundTo, roundToStep, isWithinTolerance } from "@teacharium/widget"; formatNumber(1250, "$#,##0.00", 100); // "$12.50" roundToStep(value + step, step, min); isWithinTolerance(answer, 3.14, 0.01);

What’s available at runtime

Only react and react-dom are shared with the page; Teacharium provides its own copy so there’s exactly one React. Everything else you import, including @teacharium/widget and any npm packages, is bundled into your widget. Don’t import @teacharium/player in a widget: use api.hooks instead.