This is part of the Ext JS to React blog series. You can review the code from this article on the Ext JS to React Git repo.
The toolbar container in Ext JS is a very common place to locate buttons, form fields, and other controls relating to a given view. Toolbars will commonly be docked along the edge of a panel with the remaining content filling the remaining space and scrolling separately from the toolbar. In this article, we’ll take a look at how you can create docked toolbar containers in React similar to what you’re used to in Ext JS.
Note: While not a requirement for React, this article’s code examples assume you’re starting with a starter app generated by create-react-app.
React Toolbar With a Horizontal Layout
Before we look at how to dock the toolbar within a parent container, let’s first look at how we’ll lay out items within the toolbar. Toolbars in Ext JS use hbox
and vbox
layouts for top / bottom and left / right docked toolbars respectively. We’ll use CSS Flexbox (IE11+) to manage the positioning of the items within our toolbars. This includes the negative space between items in a layout where one or more items are on one side of the tool and one or more items are on the opposite. Let’s take a look at an example toolbar with a fixed size that lays its children out in an hbox-type configuration:
import React, { Component } from 'react'; const toolbarStyle = { display: 'flex', width: '300px', backgroundColor: '#d6e2ea', padding: '6px 8px' }; class Toolbar extends Component { render() { return ( <div style={toolbarStyle}> <button>Left</button> <div style={{ flex: 1 }}></div> <button>Right</button> </div> ); } } export default Toolbar;
The Toolbar is returned in App.js:
import React from 'react'; import Toolbar from './Toolbar'; export default () => <Toolbar />;
This renders a toolbar 300px wide with 2 (visible) child items. The child items are positioned on the left and right ends of the toolbar by placing a full-flex spacer in between them.
You can review the sample code on the Git repo.
Vertical Toolbar Layout
A vertical toolbar with its items positioned at the ends can be accomplished by changing the style object slightly:
import React, { Component } from 'react'; const toolbarStyle = { display: 'inline-flex', flexDirection: 'column', height: '300px', backgroundColor: '#d6e2ea', padding: '8px 6px' }; class Toolbar extends Component { render() { return ( <div style={toolbarStyle}> <button>Top</button> <div style={{ flex: 1 }}></div> <button>Bottom</button> </div> ); } } export default Toolbar;
Then we can use Toolbar in our App:
import React from 'react'; import Toolbar from './Toolbar'; export default () => <Toolbar />;
To render a vertical toolbar we change the display
value from “flex” to an inline-flex layout. This displays the containing toolbar element as inline -vs- block, thus preventing the toolbar from taking up the width of the viewport. Then, set the flexDirection to “column” to arrange the child items in a column -vs- row. With the layout of the toolbar’s items sorted, we can move on to docking the toolbar within a parent container.
You can review the sample code on the Git repo.
Docking the Toolbar Within a Parent Component
A toolbar doesn’t have to be docked to a component outside of the scrollable view, though that’s likely the most common use case. Let’s look at how docking can be accomplished in a React component using CSS Flexbox. For our example, we’ll keep it simple by rendering a container with a single toolbar and a scrollable “body” element. First, let’s define the Toolbar component and its inline style:
import React, { Component } from 'react'; const style = { display: 'flex', backgroundColor: '#d6e2ea', padding: '6px 8px' }; class Toolbar extends Component { render() { return ( <div style={style}> <button>Left</button> <div style={{flex: 1}}></div> <button>Right</button> </div> ); } } export default Toolbar;
Our App view will be a wrapping element that houses the toolbar and enough elements to overflow the scrollable body element:
import React from 'react'; import Toolbar from './Toolbar'; import './App.css'; const panelStyle = { width: '300px', height: '300px', border: '1px solid #d6e2ea' }; const App = () => ( <div style={panelStyle} className="docked-horizontal"> <Toolbar /> <div className="body"> a<br />b<br />c<br />d<br />e<br />f<br />g<br />h<br /> i<br />j<br />k<br />l<br />m<br />n<br />o<br />p<br /> q<br />r<br />s<br />t<br />u<br />v<br />w<br />x<br /> y<br />z </div> </div> ); export default App;
The CSS used for the container, toolbar, and body element:
.docked-horizontal { display: flex; flex-direction: column; } .body { flex: 1; overflow-y: auto; padding: 8px; }
The parent container uses a flex
layout with the flex-direction
set to column
(the same technique used in our vertical toolbar). The layout places the toolbar on top of the scrollable body element with a flex
size of 1 enabling it to take up the remaining space.
You can review the sample code on the Git repo.
Vertically Docking the Toolbar
We can easily change the docking of the toolbar from top to left (or bottom / right depending on how we compose the toolbar in our React component’s JSX):
import React, { Component } from 'react'; const style = { display: 'flex', backgroundColor: '#d6e2ea', padding: '6px 8px', flexDirection: 'column' }; class Toolbar extends Component { render() { return ( <div style={style}> <button>Top</button> <div style={{flex: 1}}></div> <button>Bottom</button> </div> ); } } export default Toolbar;
We set the Toolbar style’s flex direction to “column” which arranges its newly renamed “Top” and “Bottom” buttons in a vertical stack. The App component goes largely unmodified from the previous example.
import React from 'react'; import Toolbar from './Toolbar'; import './App.css'; const panelStyle = { width: '300px', height: '300px', border: '1px solid #d6e2ea' }; const App = () => ( <div style={panelStyle} className="docked-vertical"> <Toolbar /> <div className="body"> a b c d e f g h i j k l m n o p q r s t u v w x y z </div> </div> ); export default App;
The className
prop is set to “docked-vertical” and the body contents are modified to demonstrate horizontal scrolling instead of vertical scrolling. Finally, we update the CSS for the App element wrapping the toolbar and body content:
.docked-vertical { display: flex; } .docked-vertical .toolbar { display: inline-flex; flex-direction: column; } .body { flex: 1; overflow-x: auto; padding: 8px; white-space: nowrap; }
With that, our toolbar is aligned on the left-hand side of the parent container and its child items are arranged as we’d expect from a left or right-docked toolbar. Thank you, flexbox!
You can review the sample code on the Git repo.
Conclusion
The toolbar component is a staple in Ext JS applications, so it’s nice to see that implementing its functionality in React is fairly trivial. Once you’ve used flexbox a few times you’ll see just how capable it is in laying out your child items the way you’re used to being able to do with Ext JS’s box layouts including docking. You may also want to look at some of the pre-built solutions in the React community, such as react-bootstrap, semantic-ui-react, or material-ui. In our next blog post, we’ll look at how we can implement other aspects commonly associated with the Panel component in Ext JS.
Seth Lemmons
Related Posts
-
Ext JS to React: Migration to Open Source
Worried about Migrating from Ext JS? Modus has the Answers Ideraโs acquisition of Sencha has…
-
Ext JS to React: FAQ
This is part of the Ext JS to React blog series. React is Facebook's breakout…