Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Create and Style Custom Components


As with most development, there are many ways for you to approach your customizations on top of Flex. These guidelines are based on our experience building Flex Plugins.


Custom Components

custom-components page anchor

When building a new component, we recommend following the conventions demoed by the Plugin Builder. Create a directory within /src/components, and then a trio of files to represent the content and styles of your component.


_10
src
_10
├── components
_10
│ └── MyComponent
_10
│ │ └── MyComponent.jsx
_10
│ │ └── MyComponent.Container.js
_10
│ │ └── MyComponent.Styles.js

In this example:

  • MyComponent.jsx will return a React component that could be added by one of Flex's Content.add() APIs
  • MyComponent.Container.js connects the presentational component ( MyComponent.jsx ) to the Redux store
  • MyComponent.Styles.js manages the styles you will apply to your component and its children

Using Twilio Paste

using-twilio-paste page anchor

Flex UI 2.0 leverages Twilio Paste(link takes you to an external page) for many of its components. To learn more, refer to Use Twilio Paste with a Flex Plugin.


We've found it easier to manage plugin development when your styles and your code are bundled together as part of your plugin. We recommend using Emotion(link takes you to an external page) for managing the styles of your custom components. If you choose to use Emotion, make sure to include it in your package.json dependencies.

We suggest defining a component-level style wrapper for each of your components. However, if the same styles are applied on the same type of element or you want to do dynamic styling, create separate styled components for better reusability.

Following the file structure above, we recommend keeping your styles alongside your components in files such as MyComponent.Styles.js.

There are many ways you can use Emotion to style your components. We suggest using styled(link takes you to an external page) to define a component-level style wrapper. This styled component will include all of the styles for your main component and its children.


_40
// Panel.ts
_40
import React from 'react';
_40
import { PanelStyles } from './Panel.Styles';
_40
_40
const Panel = () => {
_40
return (
_40
<PanelStyles>
_40
<ul>
_40
<li className="first-item">A</li>
_40
<li className="second-item">B</li>
_40
<li className="third-item">C</li>
_40
</ul>
_40
</PanelStyles>
_40
);
_40
};
_40
_40
export default Panel;
_40
_40
// Panel.Styles.ts
_40
import { styled } from "@twilio/flex-ui";
_40
_40
export const PanelStyles = styled('div')`
_40
text-align: center;
_40
background: #D8BFD8;
_40
color: #fff;
_40
height: 100%;
_40
_40
ul {
_40
Padding-top: 10px;
_40
}
_40
.first-item {
_40
font-size: 30px;
_40
}
_40
.second-item {
_40
font-size: 40px;
_40
}
_40
.third-item {
_40
font-size: 50px;
_40
}
_40
`;

This approach also introduces useful conventions:

  • Using classnames over individually styled elements favors using HTML elements whose semantics are clearer and more familiar to developers
  • When an element has a classname, it's easy to infer that it is only styled with CSS and there is no custom functionality.

styled can also be used to implement dynamic styles based on props. The Flex theme is automatically accessible within styled components via props.theme because Flex UI wraps all of its components in a ThemeProvider. You can also use this approach to pass in custom props, like bgColor in the example below.


_19
// MyView.Styles.ts
_19
import { styled, Theme as FlexTheme } from "@twilio/flex-ui";
_19
_19
export const SubHeader = styled('div')<{ bgColor: string, theme?: FlexTheme }>`
_19
color: ${props => props.theme.tokens.textColors.colorText};
_19
background-color: ${props => props.bgColor};
_19
font-weight: bold;
_19
text-transform: uppercase;
_19
`;
_19
_19
// MyView.tsx
_19
render() {
_19
return (
_19
<div>
_19
<SubHeader bgColor="red">This font color should be red.</SubHeader>
_19
<SubHeader bgColor="blue">This font color should be blue.</SubHeader>
_19
</div>
_19
);
_19
}

To add global styles to your plugin, use injectGlobal from Emotion. We suggest keeping a separate file for your global styles and importing it in your top-level plugin.


_14
// GlobalStyles.ts
_14
import { injectGlobal } from 'react-emotion';
_14
_14
injectGlobal`
_14
.block {
_14
display: block;
_14
}
_14
.inline-block {
_14
display: inline-block;
_14
}
_14
`;
_14
_14
// MyPlugin.tsx
_14
import '../common/GlobalStyles.ts

Using a CSS file with your plugin

using-a-css-file-with-your-plugin page anchor

You can also declare your styles in a CSS file and import that into a JS file for your global styles.


_10
// GlobalStyles.js
_10
import { injectGlobal } from 'react-emotion';
_10
import global from './global.css';
_10
injectGlobal`
_10
${global}
_10
`;


_10
/* global.css */
_10
.Twilio-SidePanel-Custom-Container {
_10
height: 100%;
_10
border: 1px blue;
_10
}

You can then use displayName to load a stock Flex component (like the SidePanel(link takes you to an external page)) and dynamically set its CSS class name based on the string that you set.


_13
<Container>
_13
<StyledSidePanel
_13
displayName="Custom"
_13
themeOverride={theme && theme.OutboundDialerPanel}
_13
handleCloseClick={handleClose}
_13
title={title}
_13
>
_13
<ListContainer
_13
itemList={itemList}
_13
itemType={itemType}
_13
/>
_13
</StyledSidePanel>
_13
</Container>

In this example, the styles you've declared within .Twilio-SidePanel-Custom-Container in your CSS file will be applied.


It may not always be practical to define your styles alongside each component. Maybe you are using shared stylesheets across a suite of applications. Or maybe you're building multiple plugins that should share a central CSS asset.

The loadCSS and loadJS methods from flex-plugin can be used in these situations to load external resources when initializing your plugin.


_12
import { FlexPlugin, loadCSS, loadJS } from 'flex-plugin';
_12
_12
export default class AdminPlugin extends FlexPlugin {
_12
constructor() {
_12
super('AdminPlugin');
_12
}
_12
_12
public init(flex, manager) {
_12
loadCSS('https://dancing-owl-1234.twil.io/assets/test.css');
_12
loadJS('https://dancing-owl-1234.twil.io/assets/test.js');
_12
}
_12
}

One difficulty with this approach is ensuring that your external URLs can be used in whichever environment you're deploying your plugin. For example, you wouldn't want to re-build your plugin if the styles depend on versioned URLs or if the assets are different in your development vs. production environment.

One approach is to use the Flex Configuration API to store the URLs as attributes, and then to reference these attributes from within your plugin.


_10
curl https://flex-api.twilio.com/v1/Configuration -X POST -u ACxxx:auth_token \
_10
-H 'Content-Type: application/json' \
_10
-d '{
_10
"account_sid": "ACxxx",
_10
"attributes": {
_10
"stylesheet_url": "https://my-external-site.com/styles.css"
_10
}
_10
}'


_10
public init(flex, manager) {
_10
loadCSS(manager.serviceConfiguration.attributes.stylesheet_url);
_10
}


Rate this page: