Framework can import custom JavaScript/ES6 modules from the front-end. Module functions can be triggered from the back-end.

Importing an ES6 module

Similarly to stylesheets, front-end scripts are imported via Framework’s mail capability. This allows you to trigger an import for all or specific sessions at any time during runtime. When the import_frontend_module method is called, this triggers a dynamic import() call in the front-end.

The import_frontend_module method takes the module_key and specifier arguments. The module_key is an identifier used to store the reference to the module, which will be used later to call the module’s functions. The specifier is the path to the module, such as /static/mymodule.js. It needs to be available to the front-end, so storing in the /static/ folder is recommended.

The following code imports a module during event handling.

def handle_click(state):
    state.import_frontend_module("my_script", "/static/mymodule.js")

If you want the module to be imported during initialisation, use the initial state.

initial_state = wf.init_state({
    "counter": 1

initial_state.import_frontend_module("my_script", "/static/mymodule.js")

Use versions to avoid caching. Similarly to stylesheets, your browser may cache modules, preventing updates from being reflected. Append a querystring to invalidate the cache, e.g. use /static/script.js?3.

Writing a module

The module should be a standard ES6 module and export at least one function, enabling it to be triggered from the back-end. As per JavaScript development best practices, modules should have no side effects. An example of a module is shown below.

let i = 0;

export function sendAlert(personName) {
    alert(`${personName}, you've been alerted. This is alert ${i}.`);

Calling a function

Once the module is imported, functions can be called from the back-end using the call_frontend_function method of state. This function takes three arguments. The first, module_key is the identifier used to import the module. The second, function_name is the name of the exported front-end function. The third, args is a List containing the arguments for the call.

The following event handler triggers the front-end function defined in the section above.

def handle_click(state):
    state.call_frontend_function("mymodule", "sendAlert", ["Bob"])

Import a JS script

Framework can also import and run JavaScript scripts directly, for their side effects. These are imported via the report’s import_script method. This method takes two arguments. The first, script_key is the identifier used to import the script. The second, path is the path to the file. The specified path must be available to the front-end, so storing it in your application’s ./static folder is recommended.

initial_state = wf.init_state({
    "counter": 1

initial_state.import_script("my_script", "/static/script.js")

Prefer ES6 modules: importing scripts is useful to import libraries that don’t support ES6 modules. When possible, use ES6 modules. The import_script syntax is only used for side effects; you’ll only be able to call functions from the back-end using modules that have been previously imported via import_frontend_module.

Importing a script from a URL

Framework can also import scripts and stylesheets from URLs. This is useful for importing libraries from CDNs. The import_script and import_stylesheet methods take a url argument, which is the URL to the script or stylesheet.

initial_state = wf.init_state({
    "my_app": {
        "title": "My App"

initial_state.import_script("lodash", "")

Frontend core

Effectively using Framework’s core can be challenging and will likely entail reading its source code. Furthermore, it’s considered an internal capability rather than a public API, so it may unexpectedly change between releases.

You can access Framework’s front-end core via globalThis.core, unlocking all sorts of functionality. Notably, you can use getUserState() to get values from state.

export function alertHueRotationValue() {
    const state = globalThis.core.getUserState();
    console.log("State is", state);