How to create a “twitter like” remaining characters count with React

17,678

Solution 1

Here is a rough version of what you wanted. Doesn't handle when chars_left goes below zero, but should be easy to implement.

var TwitterInput = React.createClass({
    getInitialState: function() {
        return {
            chars_left: max_chars
        };
    },
    handleChange(event) {
        var input = event.target.value;
        this.setState({
            chars_left: max_chars - input.length
        });
    },
    render: function() {
        return (
            <div>
                <textarea onChange={this.handleChange.bind(this)}></textarea>
                <p>Characters Left: {this.state.chars_left}</p>
            </div>
        );
    }
});

https://jsfiddle.net/terda12/b0y4jL6t

Solution 2

I have made a version too,

I am using styled-components for styling.

import React from "react";
import styled from "styled-components";

class CharCountInput extends React.Component {
  state = {
    charsLeft: null
  };

  componentDidMount() {
    this.handleCharCount(this.props.value);
  }

  handleCharCount = value => {
    const { maxChars } = this.props;
    const charCount = value.length;
    const charsLeft = maxChars - charCount;
    this.setState({ charsLeft });
  };

  handleChange = event => {
    this.handleCharCount(event.target.value);
    this.props.onChange(event);
  };

  renderCharactersLeft = () => {
    const { charsLeft } = this.state;

    let content;
    if (charsLeft >= 0) {
      content = <SpanOK>{`characters left: ${charsLeft}`}</SpanOK>;
    } else if (charsLeft != null && charsLeft < 0) {
      const string = charsLeft.toString().substring(1);
      content = <SpanError>{`too many characters: ${string}`}</SpanError>;
    } else {
      content = null;
    }
    return content;
  };

  render() {
    const { onBlur, value, type, name, placeholder } = this.props;

    return (
      <Div>
        <Input
          onChange={this.handleChange}
          value={value}
          type={type}
          name={name}
          placeholder={placeholder}
        />
        {this.renderCharactersLeft()}
      </Div>
    );
  }
}

export default CharCountInput;

const Div = styled.div`
  display: flex;
  flex-direction: column;
`;

const Input = styled.input`
  box-sizing: border-box;
  display: block;
  padding: 7px;
  width: 100%;
  margin: 0 0 0.1rem 0;
  border: 1px solid blue;
  border-radius: 7px;
  font: inherit;
  outline: none;

  &:focus {
    box-shadow: 0 0 4px blue;
  }
`;

const Span = styled.span`
  align-self: flex-end;
  font-size: 0.9rem;
  margin: 0 8px 10px 0;
`;

const SpanOK = styled(Span)`
  color: black;
`;

const SpanError = styled(Span)`
  color: red;
`;

And inside your form:

<CharCountInput
  onChange={this.handleChange}
  value={this.state.title}
  type="text"
  maxChars={150}
  name="title"
  placeholder="Enter text here..."
/>
Share:
17,678
ghostCoder
Author by

ghostCoder

Love to code and explore. Check out http://thecamelcase.com/

Updated on June 28, 2022

Comments

  • ghostCoder
    ghostCoder almost 2 years

    I'm looking to make a react counter with "target character count" for a textarea just like Twitter's does, which reduces as the user types.

    For example, on the "Meta Description" field, the target character count is 160. So, if the field is blank, the number would be 160. As the user types, the count is decreased with each character added to the input field until it reaches zero.

    If the count is higher than the target, the numbers are written in red with a minus sign in front (again, just like twitter).

    One way to do this is the listen to the onChange event on the textarea, and update the state of the component (which has the textarea and the counter), and then use that to calculate length and render the remaining char counter.

    Is there a more efficient way?