Widget API
User interfaces have complex structure and domain logic, and it can be tricky to put different widgets in common rules.
Widgets API is a protocol that describes the high level API abstraction for any widget. Having the common API shape helps us:
- simplify widget integration
- focus on widget logic
- have a standard and common language
Main building blocks
Any widget can be described with the following set of entities:
- Config
- State
- Data
- Providers
- Events
With these 5 blocks you can set up how the widget will look like, its initial behavior, subscribe to data it exposes, provide data sources and listen or produce atomic events. Let's dive deep in all of these blocks to make it clear why and when we have to use each of them
Config
Config is a clear and self-explanatory name — it does exactly what it suggests: configuration. But how we can understand what should be a part of config?
Let's take a look at Watchlist widget. What can we configure here? For example:
- available symbol categories
- available columns
- download features
- table features (sort, filters, resize)
All of these values control widget's behavior and available functionality. And it is important that these settings can't be interactively changed by end user through widget itself. Config can be changed dynamically, but only as a part of widget integration
Also, there are other cases when you need the config as well:
- environment variables, like
account idorsymbolif there is no symbol selector or symbol lookup inside the widget - locale settings (language or locale for dates or numbers)
- timezone (if there's no way to change it by interacting with the widget)
Simple check
If the value sets behaviour of your widget and can't be changed in UI
Config has two types of values:
- Optional. Widget will fall back a default value if not provided. You can check what's the default for a particular
Configproperty in widget's documentation - Required. Widget will fail to initialize if the value is not provided
State
State describes the shape of your widget's interactive and mutable data (i.e. the data that user can change directly by interacting with widget's interface).
Going back to our Watchlist widget example, we can say that state is:
- symbols in the list
- current selected symbol
- selected columns
- selected filters and sorting
All of these values are dynamic and can be changed by user interface. You are able to set them on widget start as initial value, or change during the widget lifetime as a part of widget integration, but you have to keep in mind that user can change it as well
When you create a complex application, it would be good to save state changes in a store, to be able to restore them as is, after application reload. You can find more detailed information about state persistence here.
Simple check
If the value can be changed in the widget UI
Data
Data is an advanced concept introduced to allow complex runtime interactions between widgets.
Data lets you share runtime-generated (or calculated) bits of information with programmatic actors outside the widget (e.g. with other widgets or external systems) to make all kinds of integrations.
Simple example of Data can be found in Radar widget.
This widget is an advanced symbol lookup that gives user a huge set of instruments to search the market by particular market metric criteria.
There are some cases when you want to be able to share the result of the lookup with another widget or system.
Data is a simple stream of values you can easily subscribe to.
Simple check
If the value can't be changed in the widget UI directly, but value is produced by the widget and is necessary for integration
Data providers
Data providers describes some instructions how to get data for your widget.
Providers can be a combination of different URL-paths and access-tokens or an interface with different services that widget needs to request all necessary data
Examples:
const providers = {
yourServiceUrl: '/path/to/your/service',
}
const providers = {
yourService: {
getData: (params) => {
// ...
},
},
}
More detailed examples you can see here
Simple check
If you need to describe data source for your widget
Events
Events describes the communication protocol to simplify integration or delegate some functionality outside the widget.
Most of the cases of integration can be solved with State and Data handling, but there are some cases when you need to work with some atomic and simple events.
These events work in the same way as native JavaScript events (or Redux actions), which are stateless and abstract.
All you need is just describe an event type and some payload which can be useful to process this event.
As an example, we can imagine an integration of Watchlist widget with some kind of Order entry widget.
In this situation you want to have a simple Watchlist widget without trading logic and delegate this functionality to Order entry Widget,
for example by clicking on the last price column. So, to achieve it you need:
- describe Watchlist output event on column click
- describe Order entry input event to handle buy or sell operations
- integrate these widgets and map Watchlist events to Order entry events
Simple check
If you need to provide some atomic and stateless events or process events produced outside
In SPA applications events can be useful to delegate routing outside the widget