Widgets
Widgets are iframe-based HTML objects that can be embedded on any website. This allows third parties to easily integrate Drillster's functionality into third-party learning management systems (LMS), intranets, portals, and web applications.
Available widget types
Currently, the following widget types are available:
| Widget | CSS class | Description |
|---|---|---|
| Player widget | drl-player |
Plays drills, stories, tests, and courses. The player is the interactive learning interface for end users. |
| Tile widget | drl-tile |
Displays a dynamic, responsive tile for a drill, story, course, or test object. |
| Identity widget | drl-identity |
Displays the current user's profile and avatar, or presents login/account action buttons. |
| Repertoire widget | drl-repertoire |
Displays the user's complete learning repertoire, with an optional search facility. |
| Subscription widget | drl-subscription |
Displays the details and contents of a catalog or group subscription, with optional search. |
| Access code widget | drl-access-code |
Presents a form allowing users to redeem a group access code. |
Embedding widgets in HTML
Basic HTML structure
To place a widget on your page, ensure that you reference the widget loader script and add a
<div> element with the drl-widget class and the specific widget type class:
<div class="drl-widget drl-player" id="my-id" drl-code="ABCDEF123456"></div>
⚠️ Always use a unique ID
Always give each widget a unique
idattribute. Theidis transmitted to the widget iframe and returned in event messages as the event'sorigin. It is also used when targeting widgets viadrillster.widgets('#my-id').
Widget attributes
Widgets accept various configuration attributes prefixed with drl-:
| Attribute | Scope | Description |
|---|---|---|
id |
All | Unique identifier for the widget element. Returned in event origin. |
autoload |
All | Controls whether the widget loads automatically on DOM ready ("true", default) or waits for manual trigger ("false"). |
drl-token |
All | Optional OAuth authentication token for delegated login. |
drl-locale |
All | Overrides the language for this specific widget (e.g., "en", "nl", "fr", "es", "de"). Standard HTML lang is also supported. |
drl-code |
drl-player, drl-tile, drl-subscription |
Code of the playable object, tile, or subscription. Required for player widgets. |
(For widget-specific options such as search toggles or display preferences, refer to each individual widget's documentation).
Autoload control
By default, all widgets on the page load automatically when the DOM is ready. If you want to delay loading a widget
(e.g. inside a modal dialog, hidden tab, or accordion) you can use autoload="false":
<div class="drl-widget drl-player" id="modal-player" drl-code="ABCDEF123456" autoload="false"></div>
Widgets with autoload="false" remain uninitialized until explicitly loaded via JavaScript:
// Load a specific deferred widget
drillster.widgets('#modal-player').load();
// Or load all remaining deferred widgets at once
drillster.loadRemainingWidgets();
Localization & language precedence
Drillster widgets automatically resolve their language using the following precedence:
- Widget-level
drl-locale:<div class="drl-widget ..." drl-locale="fr">takes highest precedence. - Widget-level
lang:<div class="drl-widget ..." lang="fr">is checked ifdrl-localeis omitted. - Page-level
<html lang="...">: If neither widget attribute is provided, the loader inherits the language defined on the root document (e.g.,<html lang="nl">). - Default fallback: If no language is defined anywhere, the Drillster default language is used.
Widget loader
The widget loader is a lightweight JavaScript library that initializes widgets, injects their responsive iframes, and
facilitates bidirectional cross-window messaging (using postMessage).
Script inclusion
Include the loader script once per page, preferably just before the closing </body> tag or in the <head> with
defer:
<script src="https://www.drillster.com/widgets/loader.js" type="text/javascript"></script>
The script is served with caching headers, so subsequent page visits do not incur network overhead.
JavaScript API Reference
Once loader.js is included, the global window.drillster object becomes available.
Widgets selector
The drillster.widgets([selector]) returns a widgets controller instance bound to the specified widget(s).
// Target all widgets on the page
const all = drillster.widgets();
// or
const all = drillster.widgets('*');
// Target a specific widget by ID (with or without #)
const player = drillster.widgets('#player-1');
const tile = drillster.widgets('tile-summary');
// Target widgets matching a wildcard
const lessonTiles = drillster.widgets('tile-*');
Selector & pattern matching rules
- Leading
#: Stripped automatically.drillster.widgets('#player-1')anddrillster.widgets('player-1')behave identically. - Wildcard matching (
*): The loader matches selectors using glob wildcard logic.tile-*matches any widget whose ID starts withtile-. - Anchor matching: Selectors match the full ID from start to end (
^...$). - Event selector matching: In
.on(eventSelector, callback), wildcards and regex alternation groups are supported (e.g.,'*','PLAY_*', or'(INITIALIZED|READY)').
Lifecycle management
Widgets may be loaded or unloaded with .load([token]) and .unload().
Loading with widgets.load([token])
Loads all matching widgets. If an iframe is already loaded for an element, repeated calls to .load() log a warning and avoid
re-injecting duplicate iframes.
// Load a widget manually
drillster.widgets('#player-1').load();
// Load a widget with an authentication token
drillster.widgets('#player-1').load('YOUR_OAUTH_TOKEN');
Unloading with widgets.unload()
Unloads all matching widgets, clearing their DOM contents and resetting their state so they can be reloaded later if needed.
// Unload a widget when closing a modal
drillster.widgets('#player-1').unload();
Event listening
The .on(eventSelector, callback) function may be used to subscribe to events matching the event selector from the
widgets matched by the selector.
drillster.widgets('#player-1').on('QUESTION_ANSWERED', function(event) {
console.log('Question answered in player-1:', event.data);
});
// Listen to multiple event types using alternation:
drillster.widgets().on('(INITIALIZED|COMPLETED)', function(event) {
console.log('Event received:', event.type, 'from:', event.origin);
});
Unsubscribing / event listener teardown
Calling .on(...) returns an unregister function. In Single Page Applications (React, Vue, Angular, Svelte), call
this function during component teardown to prevent memory leaks:
// Register listener and retain unregister callback
const unregister = drillster.widgets('#player-1').on('PROGRESS', handleProgress);
// In component unmount / cleanup:
unregister();
DOM scanning with drillster.scanForWidgets()
When building single-page applications or dynamically injecting widget containers into the DOM via JavaScript after page load:
// Injected a new widget container dynamically
const div = document.createElement('div');
div.className = 'drl-widget drl-tile';
div.id = 'dynamic-tile';
div.setAttribute('drl-code', 'XYZ789');
document.getElementById('container').appendChild(div);
// Tell the loader to scan and initialize newly added widgets
drillster.scanForWidgets();
Batch loading with drillster.loadRemainingWidgets([token])
Initializes all widgets marked with autoload="false" that have not yet been loaded. Accepts an optional
authentication token to apply across all remaining widgets:
// Authenticate and load all remaining widgets at once
drillster.loadRemainingWidgets('YOUR_OAUTH_TOKEN');
Inspection
Widgets referenced on the page may be inspected using drillster.getWidgets() and drillster.getRemainingWidgets()
Returns an array of all DOM elements on the page carrying the drl-widget class, or specifically those that are
pending deferred loading (autoload="false"):
// All widgets
const widgetElements = drillster.getWidgets();
console.log('Found', widgetElements.length, 'widgets on the page');
// Remaining deferred widgets pending load
const remaining = drillster.getRemainingWidgets();
console.log('Pending deferred widgets:', remaining.length);
Accessing the global context
The functions drillster.getGlobalContext() and drillster.resetGlobalContext() are available to inspect the global
context.
Inspects and resets global context defaults (such as inherited locale from ) and clears registered
deferred widgets:
// Check current global context
const context = drillster.getGlobalContext();
console.log('Global context:', context); // e.g. { locale: 'nl' }
// Reset global context and remaining widgets registry
drillster.resetGlobalContext();
drillster.resetRemainingWidgets();
Client-side events
During operation, widgets emit messages via the browser postMessage protocol. The widget loader validates origins and
forwards typed event objects to registered listeners.
Event structure
All event callbacks receive an event object with the following shape:
{
"type": "QUESTION_ANSWERED",
"origin": "player-1",
"data": {
"correct": true,
"evaluation": 100
}
}
type(string): Name of the event (e.g.INITIALIZED,QUESTION_ANSWERED,COMPLETED,UNAUTHENTICATED).origin(string): Theidattribute of the widget element that emitted the event. If the widget element did not have anid, this is set to"UNKNOWN".data(object | null): The payload data specific to the event. If the event does not carry a payload,dataisnull(orundefined).
Widget origins
Because origin matches the HTML element's id, you can distinguish events across multiple widgets on the same page:
drillster.widgets('*').on('*', function(event) {
if (event.origin === 'player-1') {
// Handle events for player 1
} else if (event.origin === 'player-2') {
// Handle events for player 2
}
});
Console debugging tip
To monitor all events emitted across all widgets on a page in real time, run this one-liner in your browser's developer console:
drillster.widgets('*').on('*', function(e) { console.log('[Drillster Event]', e); });
Delegated logins & authentication
When embedding widgets for authenticated users, you can pass an OAuth token obtained through the Drillster REST API.
Passing tokens via HTML attribute
Include the drl-token attribute on the widget's container:
<div class="drl-widget drl-player" id="player-1" drl-code="ABCDEF123456" drl-token="USER_ACCESS_TOKEN"></div>
Passing tokens via JavaScript API
For higher security—or when tokens are retrieved asynchronously via AJAX/fetch—avoid putting tokens directly in HTML.
Instead, set autoload="false" and pass the token when calling .load() or loadRemainingWidgets():
<div class="drl-widget drl-player" id="player-1" drl-code="ABCDEF123456" autoload="false"></div>
async function initPlayer() {
const token = await fetchUserDrillsterToken();
drillster.widgets('#player-1').load(token);
}
initPlayer();
When widgets emit an UNAUTHENTICATED event (e.g. if a token expires), your page can listen for the event, acquire a
fresh token, and re-authenticate widgets seamlessly.
Last updated on