Counter

A simple counter plugin for all your counting needs. You can even set a limit to change the color past a certain threshold.

Usage

To use, simply import and instantiate the counter plugin, and then use one of the available counter components in your JSX. Out of the box, the following counters are included:

  • Character Counter
  • Word Counter
  • Line Counter
  • Custom Counter

The Custom Counter allows you to bring your own counting function. This will be a function that takes plain text (as a string) from the editor as input and returns a numerical value.

Supported Environment

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

Getting Started

npm install @draft-js-plugins/editor
npm install @draft-js-plugins/counter
gettingStarted.js
// It is important to import the Editor which accepts plugins.
import Editor from '@draft-js-plugins/editor';
import createCounterPlugin from '@draft-js-plugins/counter';
import React from 'react';

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

// Extract a counter from the plugin.
const { CharCounter } = counterPlugin;

// The Editor accepts an array of plugins. In this case, only the counterPlugin is
// passed in, although it is possible to pass in multiple plugins.
// The Counter is placed after the Editor.
const MyEditor = ({ editorState, onChange }) => (
  <div>
    <Editor
      editorState={editorState}
      onChange={onChange}
      plugins={[counterPlugin]}
    />
    <CharCounter editorState={this.state.editorState} limit={200} />
  </div>
);

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-plugins/counter/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-plugins/counter/lib/plugin.css';
  • 4. Restart Webpack.

Configuration Parameters

theme
Javascript object of CSS classes with the following keys.
counter: CSS class to be applied to the number displayed when not over the specified limit
counterOverLimit: CSS class to be applied to the number displayed when over the specified limit

Component Properties

limit
A limit to indicate to the user that a threshold has passed.
countFunction
A custom counting function for the Custom Counter. The function will receive plain text from the editor (as a string) as input and should return a numerical value.

Simple Example

This editor has counters below!
Try typing here and watch the numbers go up. 🙌

Note that the color changes when you pass one of the following limits:
- 200 characters
- 30 words
- 10 lines

183 characters
37 words
8 lines
37 words (custom function)


SimpleCounterEditor.js
import React, { Component } from 'react';
import Editor, { createEditorStateWithText } from '@draft-js-plugins/editor';
import createCounterPlugin from '@draft-js-plugins/counter';
import editorStyles from './editorStyles.module.css';

const counterPlugin = createCounterPlugin();
const { CharCounter, WordCounter, LineCounter, CustomCounter } = counterPlugin;
const plugins = [counterPlugin];
const text = `This editor has counters below!
Try typing here and watch the numbers go up. 🙌

Note that the color changes when you pass one of the following limits:
- 200 characters
- 30 words
- 10 lines
`;

export default class SimpleCounterEditor extends Component {
  state = {
    editorState: createEditorStateWithText(text),
  };

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

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

  customCountFunction(str) {
    const wordArray = str.match(/\S+/g); // matches words according to whitespace
    return wordArray ? wordArray.length : 0;
  }

  render() {
    return (
      <div>
        <div className={editorStyles.editor} onClick={this.focus}>
          <Editor
            editorState={this.state.editorState}
            onChange={this.onChange}
            plugins={plugins}
            ref={(element) => {
              this.editor = element;
            }}
          />
        </div>
        <div>
          <CharCounter limit={200} /> characters
        </div>
        <div>
          <WordCounter limit={30} /> words
        </div>
        <div>
          <LineCounter limit={10} /> lines
        </div>
        <div>
          <CustomCounter limit={40} countFunction={this.customCountFunction} />
          <span> words (custom function)</span>
        </div>
        <br />
        <br />
      </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;
}

Themed Example

This editor has counters below!
Try typing here and watch the numbers go up. 🙌

Note that the color changes when you pass one of the following limits:
- 200 characters
- 30 words
- 10 lines

183 characters
37 words
8 lines
37 words (custom function)


CustomCounterEditor.js
import React, { Component } from 'react';
import Editor, { createEditorStateWithText } from '@draft-js-plugins/editor';
import createCounterPlugin from '@draft-js-plugins/counter';
import editorStyles from './editorStyles.module.css';
import counterStyles from './counterStyles.module.css';

const theme = {
  counter: counterStyles.counter,
  counterOverLimit: counterStyles.counterOverLimit,
};
const counterPlugin = createCounterPlugin({ theme });
const { CharCounter, WordCounter, LineCounter, CustomCounter } = counterPlugin;
const plugins = [counterPlugin];
const text = `This editor has counters below!
Try typing here and watch the numbers go up. 🙌

Note that the color changes when you pass one of the following limits:
- 200 characters
- 30 words
- 10 lines
`;

export default class CustomCounterEditor extends Component {
  state = {
    editorState: createEditorStateWithText(text),
  };

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

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

  // eslint-disable-next-line class-methods-use-this
  customCountFunction(str) {
    const wordArray = str.match(/\S+/g); // matches words according to whitespace
    return wordArray ? wordArray.length : 0;
  }

  render() {
    return (
      <div>
        <div className={editorStyles.editor} onClick={this.focus}>
          <Editor
            editorState={this.state.editorState}
            onChange={this.onChange}
            plugins={plugins}
            ref={(element) => {
              this.editor = element;
            }}
          />
        </div>
        <div>
          <CharCounter limit={200} /> characters
        </div>
        <div>
          <WordCounter limit={30} /> words
        </div>
        <div>
          <LineCounter limit={10} /> lines
        </div>
        <div>
          <CustomCounter limit={40} countFunction={this.customCountFunction} />
          <span> words (custom function)</span>
        </div>
        <br />
        <br />
      </div>
    );
  }
}
counterStyles.css
.counter {
  color: white;
  background-color: #353535;
  display: inline-block;
  min-width: 50px;
  border-radius: 10px;
  padding: 2px;
  text-align: center;
  margin-bottom: 5px;
}

.counterOverLimit {
  color: tomato;
  background-color: #353535;
  display: inline-block;
  min-width: 50px;
  border-radius: 10px;
  padding: 2px;
  text-align: center;
  margin-bottom: 5px;
}
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;
}