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.
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.
_10src_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
Flex UI 2.0 leverages Twilio Paste 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 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
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_40import React from 'react';_40import { PanelStyles } from './Panel.Styles';_40_40const 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_40export default Panel;_40_40// Panel.Styles.ts_40import { styled } from "@twilio/flex-ui";_40_40export 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:
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_19import { styled, Theme as FlexTheme } from "@twilio/flex-ui";_19_19export 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_19render() {_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_14import { injectGlobal } from 'react-emotion';_14_14injectGlobal`_14 .block {_14 display: block;_14 }_14 .inline-block {_14 display: inline-block;_14 }_14`;_14_14// MyPlugin.tsx_14import '../common/GlobalStyles.ts
You can also declare your styles in a CSS file and import that into a JS file for your global styles.
_10// GlobalStyles.js_10import { injectGlobal } from 'react-emotion';_10import global from './global.css';_10injectGlobal`_10 ${global}_10`;
_10/* global.css */_10.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) 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 .SidePanel-Custom-Container
in your CSS file will be applied.
When you use CSS in Flex, do not use Twilio-
in any of your class names.
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.
_12import { FlexPlugin, loadCSS, loadJS } from 'flex-plugin';_12_12export 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.
_10curl 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 }'
_10public init(flex, manager) {_10 loadCSS(manager.serviceConfiguration.attributes.stylesheet_url);_10}