Using the JS API

Discourse’s JavaScript API allows themes and plugins to make extensive customizations to the user experience. The simplest way to use it is to create a new theme from the admin panel, click “Edit Code”, and then head to the JS tab.

For file-based themes, the API can be used by creating a file in the api-initializers directory. For theme’s that’s {theme}/javascripts/api-initializers/init-theme.gjs, and for plugins, it’s {plugin}/assets/javascripts/discourse/api-initializers/init-plugin.js. The content should be:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  // Your code here
});

All the available APIs are listed in the plugin-api.gjs source code in Discourse core, along with a short description and examples.

For a full tuturial, including examples of JS API usage, check out:


This document is version controlled - suggest changes on github.

37 Likes

What’s the best way to “import” as a Site Customisation? - is it just to use require?

Whilst this works:

<script type="text/discourse-plugin" version="0.1">
var HamburgerMenuComponent = require('discourse/components/hamburger-menu').default;
</script>

This does not:

<script type="text/discourse-plugin" version="0.1">
import {default as HamburgerMenuComponent2 } from 'discourse/components/hamburger-menu';

</script>

Where I get this error:

<script type="text/discourse-js-error">unknown: 'import' and 'export' may only appear at the top level (3:0)
  1 | Discourse._registerPluginCode('0.1', api => {
  2 |   
> 3 | import {default as HamburgerMenuComponent2 } from 'discourse/components/hamburger-menu';
    | ^
  4 | 
  5 | 
  6 | }); at <eval>:8695:14</script>
2 Likes

Instead of importing it, you can look it up with

api.container.lookupFactory('component:hamburger-menu')
5 Likes

Is there a way to get access to the h helper from virtual-dom in a site customization? I’m trying to add a simple dropdown widget to use in our header, and I can’t get that darned h, even though I can get createWidget

Does:

h = require('virtual-dom').h;

not work?

2 Likes

Yes it does! Works perfectly, thanks a ton!

I wouldn’t recommend doing it that way as it would likely break future compatibility. You can use this for now but I’ll try to introduce a workaround shortly that will be safer long term.

5 Likes

Makes sense, it’s kinda circumventing the whole Plugin API thing and relying on implementation details of the ES6 compilation output, both things that are Dangerous™

Anyways, I’ll definitely keep an eye out for a better solution

I’ll try to get to it soon and I’ll reply in this topic, so watch it and you’ll see :slight_smile:

4 Likes

Actually thinking about it, the decorateWidget helper gets called with an object that has the h method. How are you inserting your widget if not via a decorator?

If you could post code that would be helpful.

{{mount-widget}} in a template for a plugin outlet.

1 Like

Ah that’s clever – I didn’t think people would try that. Okay, let me try something out.

Okay, I’ve added h to the pluginApi object as long as you request plugin api v0.3:

<script type="text/discourse-plugin" version="0.3">
  console.log(api.h('b', ['hello', 'world']));
</script>

That should work for you!

https://github.com/discourse/discourse/commit/b10b6c673d5f4936d0ee107e16531df106fae75e

9 Likes

This is now deprecated as of:

1 Like

Updated here, and in a bunch of other version-controlled docs. Thanks for the heads-up @NateDhaliwal

2 Likes