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 id attribute. The id is transmitted to the widget iframe and returned in event messages as the event's origin. It is also used when targeting widgets via drillster.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:

  1. Widget-level drl-locale: <div class="drl-widget ..." drl-locale="fr"> takes highest precedence.
  2. Widget-level lang: <div class="drl-widget ..." lang="fr"> is checked if drl-locale is omitted.
  3. 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">).
  4. 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') and drillster.widgets('player-1') behave identically.
  • Wildcard matching (*): The loader matches selectors using glob wildcard logic. tile-* matches any widget whose ID starts with tile-.
  • 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): The id attribute of the widget element that emitted the event. If the widget element did not have an id, this is set to "UNKNOWN".
  • data (object | null): The payload data specific to the event. If the event does not carry a payload, data is null (or undefined).

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