A Searchable and Scrollable ColumnChooser for the React Grid

Oliver's Blog
14 March 2018

Update: I have added a feature to the demo to make the column list scrollable, and updated the post accordingly.

A customer asked me recently whether the ColumnChooser plugin for our React Grid could be customized to include a search box. A quick check of the documentation showed some properties on the component that accept building block components for individual parts.

Searchable ColumnChooser

On that basis, I built a sample. You can check it out here (click the buttons center/top in the embedded view to see the running demo):

The implementation in the file SearchableColumnChooser.js has three parts. Starting from the bottom, you can see the component body implemented like this:

<form style={formStyles}>
  <FormGroup controlId="searchText">
    <ControlLabel>Search</ControlLabel>
    <FormControl
      type="text"
      value={filter}
      placeholder="Column Title"
      onChange={e => setFilter(e.target.value)}
    />
  </FormGroup>
  <ColumnChooser.Container style={listStyles}>
    {filteredChildren}
  </ColumnChooser.Container>
</form>

The form is implemented using React Bootstrap elements, and it includes the standard rendering of the ColumnChooser.Container plugin component, with a filtered list of children.

The second part of the implementation is a call to the recompose compose helper and the withState and withPropsOnChange HOC (that’s Higher Order Component) functions.

const SearchableColumnChooser = compose(
  withState('filter', 'setFilter', ''),
  withPropsOnChange(['children', 'filter'], ({ children, filter }) => ({
    filteredChildren: children.filter(c => childMatches(c, filter))
  }))
)(...);

withState introduces a state field called filter and a corresponding setFilter function. You can see both these values in use in the component rendering above - no surprises there.

withPropsOnChange creates a prop for the component that depends on the existing props children (that’s the standard React thing) and filter (the one created just before by withState), and is re-created when either of these props changes. filteredChildren is the name of the new property, it is created as a filtered list based upon the original children, and it is eventually rendered into the ColumnChooser.Container component.

The third part of the implementation is the predicate function used to filter the child nodes:

const childMatches = (child, filter) =>
  child.props.item.column.title.toLowerCase().includes(filter.toLowerCase());

The function implements a simple case-insensitive search for the filter string entered by the end user.

Update for the scrollable list:

I add a style block used by the ColumnChooser.Container:

const listStyles = {
  overflow: 'auto',
  maxHeight: '200px'
};

With these CSS parameters, the height of the list shown by the container is restricted, and a scrollbar is shown as required.

The final bit required for the demo functionality is the line in index.js where the ColumnChooser is created. The newly created container component is passed as a property here:

<ColumnChooser containerComponent={SearchableColumnChooser} />

That’s it - try it! When you bring up the column chooser via the button in the top-right corner of the grid, it shows the search box. Enter a string and see the column list filtered down.

Please feel free to comment if you have any questions or ideas!

no comments
No Comments

Please login or register to post comments.