Menu

Overview of Flex UI programmability options

Manager

The Flex Manager is the access point for controlling your Flex instance and all of the underlying Twilio products used for communications and assigning tasks. This means that within your Flex project, you can access the TaskRouter or Chat client directly through the Flex manager.

Aside from Flex itself, Manager also gives you access to the Conversations, Sync, Voice, and TaskRouter SDKs.

How to obtain the Manager instance

You can access the manager as follows:

In the init method of your plugin

init(flex, manager) {
  // use manager here
}

In your app, by calling the getInstance method

Flex.Manager.getInstance()

or by calling the create method when initializing Flex

return Flex
  .provideLoginInfo(configuration, "#container")
  .then(() => Flex.Manager.create(configuration))
  .then(manager => {
    // use manager here
  })
  .catch(error => handleError(error));

You can check out the sample project on how to initialize Flex.

For the detailed description of Manager visit our Flex UI API docs.

Configuration

Flex UI's configuration allows you to control the way the overall app loads, as well as the behavior of individual Flex Components.

Flex Components can be modified in two ways:

  • via componentProps in the Configuration Object
  • via the defaultProps API

Using componentProps in the Configuration Object

Example

var appConfig = {

  componentProps: {
    CRMContainer: {
      uriCallback: (task) => task
        ? `https://www.bing.com/search?q=${task.attributes.name}`
        : "http://bing.com"
    }
  },
};

React defaultProps API

You may also configure default properties for components within a Plugin by using the React defaultprops API programmatically:

componentProps: { [Component Name]: { [Prop Name]: [PropValue] } }

Example

flex.CRMContainer
  .defaultProps
  .uriCallback = (task) => task
    ? `https://www.bing.com/search?q=${task.attributes.name}`
    : "http://bing.com/";

flex.MainHeader
  .defaultProps
  .logoUrl = "https://static0.twilio.com/marketing/bundles/archetype.alpha/img/logo-wordmark--red.svg";

Go to Flex UI API docs for the full desciption of Configuration object and Component props.

Learn how to modify configuration for flex.twilio.com using API in our documentation.

Overriding language strings

You can override any string by editing the strings object on the Flex Manager instance:

flex.Manager.getInstance().strings.TaskLineCallAssigned = "I am a content string!";

5. Task list - String customization_slice.png

For the full list of UI strings, see Flex UI API docs.

Templating support with Mustache-style syntax

Flex uses Handlebars for templating and supports Mustache-style syntax and expressions within content strings, ie. embedding value placeholders between double braces. Here’s an example:

manager.strings.TaskInfoPanelContent = `
<h1>TASK CONTEXT</h1>
<h2>Task type</h2>
<p>1{{task.attributes.title}}</p>
<p>2{{task.title}}</p>
<h2>Task created on</h2>
<p>{{task.dateCreated}}</p>
<h2>Task priority</h2>
<p>{{task.priority}}</p>
<h2>Task queue</h2>
<p>{{task.taskQueueName}}</p>
<hr />
<h1>CUSTOMER CONTEXT</h1>
<h2>Customer name / phone number</h2>
<p>{{task.attributes.name}}</p>
`;

Within the context of each component and string, additional dynamic content is available: for example, by accessing Task properties or attributes.

Accessing Task context: properties and attributes

Within the context of each component and string, additional dynamic content is available: for example, by accessing Task properties or attributes.

Here’s an example of the use in a template of a couple of the properties and attributes listed above:

manager.strings.TaskExtraInfo = "My task {{task.attributes.name}} was created on {{task.dateCreated}}";

Helper functions

Helper functions provide you with a way to customize text with dynamic information. Here is an example of the use of a helper function to enable dynamic updates:

manager.strings.TaskExtraInfo = "Time since last update: {{helper.durationSinceUpdate}}";

You can find all available helper functions in Flex UI API docs.

Theming Flex UI

Flex UI theming interface closely maps to the Twilio Paste design system. This structure is based on the concept of design tokens, a set of variables that you can modify. This structure promotes both consistency, customization and web accessibility.

Theme config

Theme configuration is done with config key called config.theme with the following structure

interface ThemeConfigProps {
   isLight?: boolean; // Represents if light or dark theme
   tokens?: Tokens; // Paste tokens
   componentThemeOverrides?: Object; // Object containing styles of the component which is to be overridden.
}

Component theming

For components which receive the theme as props, props.theme.tokens can be used.

Custom tokens

Use custom tokens to pass your own custom tokens to theme using the example below.

  appconfig = {
    theme: {
      tokens: {
        custom: {
          myCustomToken: "#ccc"
        }
      }
    }
  }

Paste tokens

Similarly, you can override default design tokens when using Twilio Paste for your plugin.

appConfig = {
   theme: {
       tokens: {
           backgroundColors: {
                 colorBackgroundPrimaryStrongest: "tomato",
           },
       },
   },
};

ThemeProvider

An API Flex.setProviders() can be used to load providers on the root level once and don’t have to worry about wrapping again as the context will correctly set. Now to use Paste in Flex plugins, developers will not need to wrap Paste ThemeProvider over all its components. Explore the API in our Flex UI API docs.

When using Paste, developers need to pass the CustomizationProvider from Paste to Flex using Flex.setProviders api as below. By doing this, we’ll wrap Flex with the passed Provider and developers don’t have to worry about fetching the right theme and passing it on.

import { CustomizationProvider } from "@twilio-paste/core/customization";
 
Flex.setProviders({
   PasteThemeProvider: CustomizationProvider
});
 
Flex.AgentDesktopView.Panel1.Content.add(
   <PasteButton key="A" variant="primary">
       Paste Button
   </PasteButton>
);
 
Flex.AgentDesktopView.Panel1.Content.add(
   <PasteButton key="B" variant="primary">
       Paste Button
   </PasteButton>
);

Flex.setProviders() also allows developers to pass their own custom provider which is needed to be set on the root level. They can do it as below:

Flex.setProviders({
   CustomProvider: (RootComponent) => (props) => {
       return (
           <Context.Provider value={{ test: "123" }}>
               <RootComponent {...props} />
           </Context.Provider>
       );
   }
});
 
Flex.AgentDesktopView.Panel1.Content.add(
   <Context.Consumer>
       {(value) => {
           <div>{value.foo}</div> // Will print 123
       }}
   </Context.Consumer>
);

The below example shows how to use a custom provider for styling Material UI components. Ensure this is done before declaring any components.

import { StylesProvider, createGenerateClassName } from '@material-ui/core/styles';

Flex.setProviders({
      CustomProvider: (RootComponent) => (props) => {
          return (
            <StylesProvider generateClassName={createGenerateClassName({
              productionPrefix: 'pluginXYZ',
              seed: 'pluginXYZ',
            })}>
                  <RootComponent {...props} />
              </StylesProvider>
          );
      }
});

Using Twilio Paste

Not every component you build needs to start from scratch. Existing React component libraries can help you use components that have already been built with browser compatibility, responsive screen sizes, and accessibility in mind. Internally, flex-ui leverages Twilio Paste for many of its components. You can similarly use Paste to create components that start with a similar style to Flex's existing layout.

Paste is already a dependency of flex-ui but if you choose to include it explicitly, ensure the plugin doesn't have multiple versions of Paste in its dependency tree.

UI components

Flex UI is a library of programmable or dynamic components that expose a Content property and allows you to add, replace and remove any component and its children. Each immediate child of a component has a key (required for the add and replace methods) and a set of properties that will be inherited by its children. To see the full list of components, find a component's key or explore component props, go to Flex UI API docs.

To learn more how to work with components and props, see our developer guide.

UI actions and Flex Events

The Flex UI is constantly emitting event data that describes how the user is interacting with the Flex UI. As you write Plugins, the Actions Framework allows you to harness these events and define your own logic to describe how you want the Flex UI, CRM Data, or any other data, to change. You can register events before or after an action fires, or even replace the behavior of an Action.

Learn how to use the Actions Framework in our developer documentation.

In-app and browser notifications

Flex UI provides a client-side API to manage notifications in Flex UI.

A notification is an alert that tells the user what state change or error has occurred to a component or page when they are no longer viewing that component or page

Users can be notified in Flex using a Notification Bar or Browser notifications or both.

What are notification framework capabilities?

  • Register custom notifications including browser notifications
  • Customize standard notifications
  • Turn off standard UI notifications
  • Override standard notifications per Task Channel Definition
  • Customize how standard UI notifications are displayed
  • Register your custom UI notifications and specify how to render them

To learn how to work with notifications, see our developer guide.

The full reference for the Notification Manager and a list of standard notifications are available in Flex API docs.

State Management

Flex UI 2.0 includes the Redux Toolkit and some new APIs for managing your internal state. These tools provide some guardrails for your state management, helping you set up boilerplate code more easily and with better defaults.

We recommend using single Redux store, either let Flex UI create its own store or pass a custom store using Manager.create() API

useFlexSelector

A wrapper around Redux's useSelector method. It exposes the same API but adds some Flex validations to ensure Flex's internal state is usable. This selector is specific for working with Flex state itself. Outside of accessing Flex state, we recommend using the default useSelector.

import { useFlexSelector } from "@twilio/flex-ui";

const MyComponent = (props) => {
    const viewState = useFlexSelector(state => state.flex.view);
    return (
        viewState.isSideNavOpen &&
        <div>My Custom Code</div>
    )
}

The selector takes the current view state for the custom component. The selector guarantees that the state being selected is safe to read and can be used in the application without side effects. This couldn’t be guaranteed with useSelector.

useFlexDispatch

A wrapper around Redux's useDispatch method. It prevents dispatches from causing side effects to Flex's state, ensuring your changes work as expected. Use this hook for interacting with Flex's state. You can use the native useDispatch method outside of Flex’s state.

import { useFlexDispatch, useFlexSelector } from "@twilio/flex-ui";

const MyComponent = (props) => {
   const viewState = useFlexSelector(state => state.flex.view);
   const dispatch = useFlexDispatch();
   return (
       viewState.isSideNavOpen &&
       <button onClick={() => dispatch({type: "close_side_bar"})}>My Custom Code</button>   
   )
}

Learn more about using Redux in our developer guide.

Task Channel Definitions

Flex is a multichannel contact center. We support a number of channels out-of-the-box, and are constantly adding more. We support the following native channels:

  • Voice
  • SMS with MMS support
  • WebChat with Media Attachments
  • WhatsApp

With the Task Channel Definition API you can also add custom channels and override the behavior of existing ones.

Learn more about working with Task Channel Definitions in the developer guide.

insightsClient

The insightsClient provide access to the Twilio Sync SDK. For Flex accounts, this gives access to workers and tasks data through the use of two classes:

  • LiveQuery class: to query Flex data and receives pushed updates whenever new (or updated) records would match the given expression
  • InstantQuery class: to get a static snapshot of Flex data

Both classes needs two arguments:

  • Index name: data set the query is executed against. Currently supported index names for Flex are: tr-task, tr-worker, tr-reservation, tr-queue.
  • Query: this is the query used to filter the data from the index. The syntax for the query is documented here. The query can be an empty string: in this case the whole data set is returned (e.g. all workers.)

LiveQuery example

In this example, the insightsClient is used to query the workers with activity_name set to Available and subscribe to changes. That means that every time a worker change its status to Available, an event itemUpdated is fired. If a worker changes its status from Available to any other status, the itemRemoved event is fired.

Flex.Manager.insightsClient
  .liveQuery('tr-worker', 'data.activity_name == "Available"')
  .then(function (args) {
    console.log(
      'Subscribed to live data updates for worker in "Available" activity'
    );
    args.on('itemRemoved', function (args) {
      console.log('Worker ' + args.key + ' is no longer "Available"');
    });
    args.on('itemUpdated', function (args) {
      console.log('Worker ' + args.key + ' is now "Available"');
    });
  })
  .catch(function (err) {
    console.log('Error when subscribing to live updates', err);
  });

InstantQuery example

In this example, the insightsClient is used to query the workers with specific skills inside its attributes. This returns an array of workers that can be used to provide static data.

manager.insightsClient.instantQuery('tr-worker').then((q) => {
  q.on('searchResult', (items) => {
    // Do something with the results
  });
  q.search('data.attributes.languages contains "english"');
});
Rate this page:

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.

Thank you for your feedback!

Please select the reason(s) for your feedback. The additional information you provide helps us improve our documentation:

Sending your feedback...
🎉 Thank you for your feedback!
Something went wrong. Please try again.

Thanks for your feedback!

thanks-feedback-gif