Skip to content

Portable custom interaction

Portable Custom Interaction (PCI) — hosts an IMS QTI 3 Portable Custom Interaction inside an iframe and bridges response/state/configuration between the item runtime and the PCI’s AMD module. This is the modern successor to the legacy Custom interaction (CES) mechanism.

qti-portable-custom-interaction

AttributeNotes
moduleAMD module id to load via RequireJS, e.g. "pci-getallen".
custom-interaction-type-identifierThe PCI’s type identifier (spec prefers a URN, e.g. urn:fdc:hmhco.com:pci:shading).
data-require-pathsJSON object of RequireJS paths overrides.
data-require-shimJSON object of RequireJS shim config.
data-require-js-urlA RequireJS to load inside the iframe instead of the inlined copy.
data-components-cdn-urlA qti-components bundle (ES module) to import inside the iframe, e.g. your own copy of @citolab/qti-components/cdn/index.js. Not loaded when absent.
data-components-css-urlA stylesheet to link inside the iframe, e.g. your own copy of @citolab/qti-components/item.css. Not loaded when absent.
data-base-urlBase URL prefix used to resolve module paths and assets.
any other data-*Forwarded (hyphenated key, normalized) into the PCI’s properties object.

The PCI runs in a srcdoc iframe that loads nothing from a public CDN: RequireJS and the QTI 3 shared vocabulary stylesheet (qti-layout-row, qti-well, qti-padding-*, …) are inlined from this version of qti-components. The item’s qti-stylesheets are added to the iframe as well. The only other request is the PCI module itself, from the item.

Child elements

ElementPurpose
<qti-interaction-modules> / <qti-interaction-module id="..." primary-path="...">Per-module RequireJS path overrides.
<qti-interaction-markup>Raw markup forwarded into the iframe as the PCI’s container content.
<qti-template-variable template-identifier="...">Resolves a template variable and passes it to the PCI.
<qti-context-variable identifier="...">Resolves a context variable (including QTI_CONTEXT) for the PCI.

Module contract

The author’s AMD module must call qtiCustomInteractionContext.register(pciInstance), where pciInstance implements:

interface IMSpci<T> {
typeIdentifier: string;
getInstance(dom: HTMLElement, configuration: unknown, state: T | null): void;
getResponse(): unknown;
setResponse(value: unknown): void;
getState(): T;
setState(value: T): void;
}
<qti-portable-custom-interaction
response-identifier="RESPONSE"
module="pci-getallen"
custom-interaction-type-identifier="getallenFormule"
data-base-url="/assets/qti-portable-interaction/baking_soda"
>
<qti-interaction-modules>
<qti-interaction-module id="pci-getallen" primary-path="pci-getallen.js"></qti-interaction-module>
</qti-interaction-modules>
<qti-interaction-markup></qti-interaction-markup>
</qti-portable-custom-interaction>