SideToolbar

Supported Environment

  • Desktop: Yes
  • Mobile: No
  • Screen-reader: No

Getting Started

npm install draft-js-plugins-editor
npm install draft-js-side-toolbar-plugin
gettingStarted.js
// It is important to import the Editor which accepts plugins.
import Editor from 'draft-js-plugins-editor';
import createSideToolbarPlugin from 'draft-js-side-toolbar-plugin';
import React from 'react';

// Creates an Instance. At this step, a configuration object can be passed in
// as an argument.
const sideToolbarPlugin = createSideToolbarPlugin();

// The Editor accepts an array of plugins. In this case, only the sideToolbarPlugin
// is passed in, although it is possible to pass in multiple plugins.
const MyEditor = ({ editorState, onChange }) => (
  <Editor
    editorState={editorState}
    onChange={onChange}
    plugins={[sideToolbarPlugin]}
  />
);

export default MyEditor;

Importing the default styles

The plugin ships with a default styling available at this location in the installed package:  node_modules/draft-js-side-toolbar-plugin/lib/plugin.css

Webpack Usage

  • 1. Install Webpack loaders:  npm i style-loader css-loader --save-dev
  • 2. Add the below section to Webpack config (if your config already has a loaders array, simply add the below loader object to your existing list.
    module.exports = {
      module: {
        loaders: [
          {
            test: /plugin\.css$/,
            loaders: [
              'style-loader', 'css',
            ],
          },
        ],
      },
    };
    
  • 3. Add the below import line to your component to tell Webpack to inject the style to your component.
    import 'draft-js-side-toolbar-plugin/lib/plugin.css';
    
  • 4. Restart Webpack.

Browserify Usage

Please help, by submiting a Pull Request to the documentation.

Configuration Parameters

themeObject of CSS classes with the following keys.
buttonStyles: CSS class for the buttons.
toolbarStyles: CSS class for toolbar.
blockTypeSelectStyles: CSS class for the dot.
positionString for the position to be rendered.(Default is left)

Simple Side Toolbar Example

Once you click into the text field the sidebar plugin will show up …
SimpleSideToolbarEditor.js
import React, { Component } from 'react';
import Editor, { createEditorStateWithText } from 'draft-js-plugins-editor';
import createSideToolbarPlugin from 'draft-js-side-toolbar-plugin';
import editorStyles from './editorStyles.css';

const sideToolbarPlugin = createSideToolbarPlugin();
const { SideToolbar } = sideToolbarPlugin;
const plugins = [sideToolbarPlugin];
const text = 'Once you click into the text field the sidebar plugin will show up …';

export default class SimpleSideToolbarEditor extends Component {

  state = {
    editorState: createEditorStateWithText(text),
  };

  onChange = (editorState) => {
    this.setState({
      editorState,
    });
  };

  focus = () => {
    this.editor.focus();
  };

  render() {
    return (
      <div className={editorStyles.editor} onClick={this.focus}>
        <Editor
          editorState={this.state.editorState}
          onChange={this.onChange}
          plugins={plugins}
          ref={(element) => { this.editor = element; }}
        />
        <SideToolbar />
      </div>
    );
  }
}
editorStyles.css
.editor {
  box-sizing: border-box;
  border: 1px solid #ddd;
  cursor: text;
  padding: 16px;
  border-radius: 2px;
  margin-bottom: 2em;
  box-shadow: inset 0px 1px 8px -3px #ABABAB;
  background: #fefefe;
}

.editor :global(.public-DraftEditor-content) {
  min-height: 140px;
}

Custom Side Toolbar Example

Once you click into the text field the sidebar plugin will show up …
CustomSideToolbarEditor.js
import React, { Component } from 'react';

import Editor, { createEditorStateWithText } from 'draft-js-plugins-editor';
import {
  HeadlineOneButton,
  HeadlineTwoButton,
  BlockquoteButton,
  CodeBlockButton,
} from 'draft-js-buttons';

import createSideToolbarPlugin from 'draft-js-side-toolbar-plugin';
import editorStyles from './editorStyles.css';
import buttonStyles from './buttonStyles.css';
import toolbarStyles from './toolbarStyles.css';
import blockTypeSelectStyles from './blockTypeSelectStyles.css';

// Setting the side Toolbar at right position(default is left) and styling with custom theme
const sideToolbarPlugin = createSideToolbarPlugin({
  position: 'right',
  theme: { buttonStyles, toolbarStyles, blockTypeSelectStyles }
});
const { SideToolbar } = sideToolbarPlugin;
const plugins = [sideToolbarPlugin];
const text = 'Once you click into the text field the sidebar plugin will show up …';

export default class CustomSideToolbarEditor extends Component {

  state = {
    editorState: createEditorStateWithText(text),
  };

  onChange = (editorState) => {
    this.setState({
      editorState,
    });
  };

  focus = () => {
    this.editor.focus();
  };

  render() {
    return (
      <div className={editorStyles.editor} onClick={this.focus}>
        <Editor
          editorState={this.state.editorState}
          onChange={this.onChange}
          plugins={plugins}
          ref={(element) => { this.editor = element; }}
        />
        <SideToolbar>
          {
            // may be use React.Fragment instead of div to improve perfomance after React 16
            (externalProps) => (
              <div>
                <HeadlineOneButton {...externalProps} />
                <HeadlineTwoButton {...externalProps} />
                <BlockquoteButton {...externalProps} />
                <CodeBlockButton {...externalProps} />
              </div>
            )
          }
        </SideToolbar>
      </div>
    );
  }
}
editorStyles.css
.editor {
  box-sizing: border-box;
  border: 1px solid #ddd;
  cursor: text;
  padding: 16px;
  border-radius: 2px;
  margin-bottom: 2em;
  box-shadow: inset 0px 1px 8px -3px #ABABAB;
  background: #fefefe;
}

.editor :global(.public-DraftEditor-content) {
  min-height: 140px;
}
buttonStyles.css
.wrapper {
  position: absolute;
}

.buttonWrapper {
  display: inline-block;
}

.button {
  background: #333;
  color: #ddd;
  font-size: 18px;
  border: 0;
  padding-top: 5px;
  vertical-align: bottom;
  height: 34px;
  width: 36px;
  border-radius: 4px;
}

.button svg {
  fill: #ddd;
}

.button:hover, .button:focus {
  background: #444;
  outline: 0; /* reset for :focus */
}

.active {
  color: #6a9cc9;
}

.active svg {
  fill: #6a9cc9;
}
toolbarStyles.css
.wrapper {
  position: absolute;
}
blockTypeSelectStyles.css
.blockType {
  box-sizing: border-box;
  border: 1px solid #111;
  background: #333;
  padding: 5px;
  margin: 0;
  border-radius: 18px;
  cursor: pointer;
  height: 36px;
  width: 36px;
  line-height: 36px;
  text-align: center;
}

.blockType svg {
  fill: #ddd;
}

.spacer {
  position: absolute;
  left: 50%;
  transform: translate(-50%);
  width: 74px;
  height: 8px;
}

.popup {
  position: absolute;
  left: 50%;
  transform: translate(-50%);
  border: 1px solid #111;
  background: #333;
  border-radius: 2px;
  box-shadow: 0px 1px 3px 0px rgba(220,220,220,1);
  z-index: 3;
  box-sizing: border-box;
  width: 74px;
  margin-top: 8px;
}

.popup:after, .popup:before {
  bottom: 100%;
  left: 50%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}

.popup:after {
  border-color: rgba(251, 251, 251, 0);
  border-bottom-color: #333;
  border-width: 4px;
  margin-left: -4px;
}
.popup:before {
  border-color: rgba(221, 221, 221, 0);
  border-bottom-color: #111;
  border-width: 6px;
  margin-left: -6px;
}