Skip to main content

Your first custom widget

What are widgets?#

  • They are Components that can be added to a dashboard.
  • They can be saved and reused.
  • They can accept action plugins to make them more interactive.

ActiveUI comes with many stock widgets that require no coding to use.

However, any React Component can be turned into an ActiveUI widget.

This means that we can develop our own widgets!

Your first custom widget#

We will start with a "Hello World!" to get that first bit of code on the screen.

Let's create a couple of new files inside src next to plugins.tsx.

Widget File#

The first file contains our widget Component. Since we are building a map of the world, let's name it Map.tsx.

import React, { FC } from "react";import { WidgetPluginProps } from "@activeviam/activeui-sdk";
export const Map: FC<WidgetPluginProps> = (props) => {  return <div>Hello World!</div>;};

Map is a Function Component that accepts WidgetPluginProps (but does not use them yet) and simply returns a div containing "Hello World!".

note

We will demystify WidgetPluginProps later on in this section.

Plugin Widget File#

Lets create the second file in the same location and call it pluginWidgetMap.ts.

TIP: Naming plugins

Take note of the naming here. When defining plugins its good practice to stick with the following formula:

  1. Start with "plugin".
  2. Reveal the type of "plugin". In this case it is a "widget", but it also could have been a "cell" or a "menuItem".
  3. Provide the underlying component's name . In this case we are calling it "map".

That brings us to a final name of pluginWidgetMap.

import { WidgetPlugin } from "@activeviam/activeui-sdk";
import { Map } from "./Map";
const widgetKey = "map";
export const pluginWidgetMap: WidgetPlugin = {  Component: Map,  initialState: {    widgetKey,  },  key: widgetKey,};

Let's stop a minute and decipher this.

We defined pluginWidgetMap which is a widget plugin. But what is widget plugin?

Simply put, a widget plugin is an object containing all the information needed to register a new widget in ActiveUI.

By editing this object, we can change how this widget will look and behave.

pluginWidgetMap contains three properties so far:

  • Component is the thing that actually gets displayed. In our case it is Map.
  • key identifies the widget, which will be useful when we want to display it in a dashboard.
  • initialState is a bit more complex and we will explore it more in the next section.

Extend ActiveUI#

Let's wire our new widget into ActiveUI!

  • Open up plugins.tsx.
  • Add pluginWidgetMap into the widgetPlugins array.
note

The widgetPlugins array is eventually passed to the plugin registry. This is how ActiveUI knows what plugins it has.

+ import { pluginWidgetMap } from "./pluginWidgetMap";...
// Make sure to put it at the top of `widgetPlugins` so it becomes the first widget in the Widgets Ribbon. This will make it easier to find in the coming steps.const widgetPlugins: Array<WidgetPlugin> = [+ pluginWidgetMap,  pluginWidgetPivotTable,  ...]

It worked! Our new widget appeared:

We can drag and drop it into the dashboard to see our Component:

…but there are a few strange things going on:

  • Without styling, "Hello world!" is stuck on the left edge.
  • The question mark icon in the widgets ribbon does not relate to our widget at all.
  • There are two weird labels:
    • aui.plugins.widget.map.key when you hover the map icon in the widgets ribbon.
    • aui.plugins.widget.map.defaultName in the widget's title in the upper left corner of the widget.

Let's scratch these itches before we move on.

tip

To improve your experience, save the dashboard now. Your URL will now end with /dashboard/<id> where "id" is a short string. From here on out, each time you refresh the page, you will end up directly on your widget.

Add Style#

Since Map is a React Component, we could easily hardcode a horizontal padding onto it. However, our widget can be used in other contexts (like an atoti notebook) where that hardcoded style might not look good.

For this reason, widgets accept a style prop passed in from their parents. This style prop contains all the styling needed to make a widget look good inside its parent. Now we just have to wire that styling in.

const Map: FC<WidgetPluginProps> = (props) => {  return (-    <div>+    <div style={props.style}>      Hello World!    </div>  );};

With this change, Map allows its parent (in our case, the dashboard) to control its style. Now our map will look good in a dashboard as well as in a notebook (which would pass its own style object down).

Add an icon#

Because pluginWidgetMap is a WidgetPlugin, it has an Icon property where we can attach an icon to represent our Component.

We will download a new file, IconWorld.tsx. It contains a React Component that displays a globe icon. This makes it perfect for our map! Click here to download it.

Place IconWorld.tsx next to Map.tsx and wire it into our pluginWidgetMap's Icon property:

+ import { IconWorld } from "./IconWorld";
  export const pluginWidgetMap: WidgetPlugin = {    Component: Map,+   Icon: IconWorld,    initialState: {      widgetKey,    },    key: widgetKey,  };

Add translations#

Now on to those two weird labels we spotted earlier.

Because ActiveUI is made to work with any language, it expects plugins to provide translations for all the locales it is going to support, starting with en-US.

While you can have as many translation entries as you like, the following two are required for all widgets:

  • key, used on the icon's tooltip.
  • defaultName, used as a placeholder for the widget's title.

You might be asking youself: how did they know to use key and defaultName?

These keys are actually the last words in the weird labels we spotted: aui.plugins.widget.map.key and aui.plugins.widget.map.defaultName. ActiveUI adds the other text based on what kind of plugin you're using (WidgetPlugin in our case) and the plugin's key.

Let's head back into pluginWidgetMap.ts to add a translations property to the plugin:

import { IconWorld } from "./IconWorld";
export const pluginWidgetMap: WidgetPlugin = {  Component: Map,  Icon: IconWorld,  initialState: {    widgetKey,  },  key: widgetKey,+ translations: {+   "en-US": {+     key: "Map",+     defaultName: "New map"+   }+ }};
note

You can (and should) add more translations every time you add another caption to your widget. This way, you will fully support your widget's different locales. More on this later in the tutorial. 😊

Congratulations, you just created your first ActiveUI widget!