Highly customizable React component for inputing tags.

Overview

react-tagsinput

NPM version Build Status Coverage Status Dependency Status Size Download Count js-standard-style

Highly customizable React component for inputing tags.

Table of Contents

Demo

Demo

Interactive Demo

Install

npm install react-tagsinput --save
bower install react-tagsinput --save

Example

import TagsInput from 'react-tagsinput'

import 'react-tagsinput/react-tagsinput.css' // If using WebPack and style-loader.

class Example extends React.Component {
  constructor() {
    super()
    this.state = {tags: []}
  }

  handleChange(tags) {
    this.setState({tags})
  }

  render() {
    return <TagsInput value={this.state.tags} onChange={::this.handleChange} />
  }
}

FAQ

How do I make the input dynamically grow in size?

Install react-input-autosize and change the renderInput prop to:

function autosizingRenderInput ({addTag, ...props}) {
  let {onChange, value, ...other} = props
  return (
    <AutosizeInput type='text' onChange={onChange} value={value} {...other} />
  )
}
How do I add auto suggestion?

Use react-autosuggest and change the renderInput prop to something like:

function autosuggestRenderInput ({addTag, ...props}) {
  const handleOnChange = (e, {newValue, method}) => {
    if (method === 'enter') {
      e.preventDefault()
    } else {
      props.onChange(e)
    }
  }

  const inputValue = (props.value && props.value.trim().toLowerCase()) || ''
  const inputLength = inputValue.length

  let suggestions = states().filter((state) => {
    return state.name.toLowerCase().slice(0, inputLength) === inputValue
  })

  return (
    <Autosuggest
      ref={props.ref}
      suggestions={suggestions}
      shouldRenderSuggestions={(value) => value && value.trim().length > 0}
      getSuggestionValue={(suggestion) => suggestion.name}
      renderSuggestion={(suggestion) => <span>{suggestion.name}</span>}
      inputProps={{...props, onChange: handleOnChange}}
      onSuggestionSelected={(e, {suggestion}) => {
        addTag(suggestion.name)
      }}
      onSuggestionsClearRequested={() => {}}
      onSuggestionsFetchRequested={() => {}}
    />
  )
}

A working example can be found in example/components/autocomplete.js.

How do I control the value of the input box?

Use inputValue and onChangeInput:

class Example extends React.Component {
  constructor() {
    super()
    this.state = {tags: [], tag: ''}
  }

  handleChange(tags) {
    this.setState({tags})
  }

  handleChangeInput(tag) {
    this.setState({tag})
  }

  render() {
    return (
      <TagsInput
        value={this.state.tags}
        onChange={::this.handleChange}
        inputValue={this.state.tag}
        onChangeInput={::this.handleChangeInput}
      />
    )
  }
}
How do I fix warning "unknown prop addTag"?

For ease of integration with auto complete components react-tagsinput passes the addTag method to renderInput props, if you are writing your own renderInput you need to filter addTag to not get an error about unknown prop addTag from React. Here is how it's done in the default renderInput function.

function defaultRenderInput ({addTag, ...props}) {
  let {onChange, value, ...other} = props
  return (
    <input type='text' onChange={onChange} value={value} {...other} />
  )
}
How do I copy paste from Excel?

All you need is to add a CR, carriage return, symbol (it is the default line break style in MS Office documents).

See answer on Stack Overflow.

Set the pasteSplit prop to this function:

pasteSplit(data) {
  const separators = [',', ';', '\\(', '\\)', '\\*', '/', ':', '\\?', '\n', '\r'];
  return data.split(new RegExp(separators.join('|'))).map(d => d.trim());
}

Component Interface

Props

value (required)

An array of tags.

onChange (required)

Callback when tags change, gets three arguments tags which is the new tag array, changed which is an array of the tags that have changed and changedIndexes which is an array of the indexes that have changed.

onChangeInput

Callback from the input box, gets one argument value which is the content of the input box. (onChangeInput is only called if the input box is controlled, for this to happen both inputValue and onChangeInput need to be set)

addKeys

An array of key codes that add a tag, default is [9, 13] (Tab and Enter).

currentValue

A string to set a value on the input.

inputValue

Similar to currentValue but needed for controlling the input box. (inputValue is only useful if you use it together with onChangeInput)

onlyUnique

Allow only unique tags, default is false.

validate

Allow only tags that pass this validation function. Gets one argument tag which is the tag to validate. Default is () => true.

validationRegex

Allow only tags that pass this regex to be added. Default is /.*/.

onValidationReject

Callback when tags are rejected through validationRegex, passing array of tags as the argument.

disabled

Passes the disabled prop to renderInput and renderTag, by default this will "disable" the component.

maxTags

Allow limit number of tags, default is -1 for infinite.

addOnBlur

Add a tag if input blurs. Default false.

addOnPaste

Add a tags if HTML5 paste on input. Default false.

pasteSplit

Function that splits pasted text. Default is:

function defaultPasteSplit (data) {
  return data.split(' ').map(d => d.trim())
}
removeKeys

An array of key codes that remove a tag, default is [8] (Backspace).

className

Specify the wrapper className. Default is react-tagsinput.

focusedClassName

Specify the class to add to the wrapper when the component is focused. Default is react-tagsinput--focused.

tagProps

Props passed down to every tag component. Default is:

{
  className: 'react-tagsinput-tag', 
  classNameRemove: 'react-tagsinput-remove'
}
inputProps

Props passed down to input. Default is:

{
  className: 'react-tagsinput-input',
  placeholder: 'Add a tag'
}
tagDisplayProp

The tags' property to be used when displaying/adding one. Default is: null which causes the tags to be an array of strings.

renderTag

Render function for every tag. Default is:

function defaultRenderTag (props) {
  let {tag, key, disabled, onRemove, classNameRemove, getTagDisplayValue, ...other} = props
  return (
    <span key={key} {...other}>
      {getTagDisplayValue(tag)}
      {!disabled &&
        <a className={classNameRemove} onClick={(e) => onRemove(key)} />
      }
    </span>
  )
}
renderInput

Render function for input. Default is:

function defaultRenderInput (props) {
  let {onChange, value, addTag, ...other} = props
  return (
    <input type='text' onChange={onChange} value={value} {...other} />
  )
}

Note: renderInput also receives addTag as a prop.

renderLayout

Renders the layout of the component. Takes tagComponents and inputComponent as args. Default is:

function defaultRenderLayout (tagComponents, inputComponent) {
  return (
    <span>
      {tagComponents}
      {inputComponent}
    </span>
  )
}
preventSubmit

A boolean to prevent the default submit event when adding an 'empty' tag. Default: true

Set to false if you want the default submit to fire when pressing enter again after adding a tag.

Methods

focus()

Focus on input element.

blur()

Blur input element.

accept()

Try to add whatever value is currently in input element.

addTag(tag)

Convenience method that adds a tag.

clearInput()

Clears the input value.

Styling

Look at react-tagsinput.css for a basic style.

Contributors

Changelog

License


MIT Licensed

Issues
  • Component does not re-render when props are updated

    Component does not re-render when props are updated

    As a side effect of copying props to state, when new props are sent to the component, the components state is not also updated. Example resolution:

    componentWillReceiveProps(nextProps) {
        this.setState({tags: nextProps.tags.slice(0)});
    }
    
    opened by amoenk 11
  • Asynchronous validation?

    Asynchronous validation?

    Hi!

    First, thanks for this repo; it's been very easy to integrate this component into a form I'm building.

    I was wondering if you had any suggestions for how to handle async validation? I'm using react-tagsinput to let user enter a list of usernames. I need to validate those username against a REST API. It doesn't look like it would work out-of-the-box; addTag calls validate and expects a synchronous response. There's also the question of what to do with an invalid tag when an async response comes back.

    opened by grahamb 10
  • More Context in onChange

    More Context in onChange

    Would be good to have more context in onChange. For example, the ability to know what value was changed specifically. This would make it much easier to implement into a redux-form like environment. Right now I get an array of tags but have no idea what values were actually modified, etc so I can't really send the changed values to redux form very well.

    opened by bradennapier 9
  • Issues using autocomplete

    Issues using autocomplete

    This issue appears on example/index.html file from this repo. When you click on AutocompleteExample (not in the middle but near border) the error is thrown:

    bundle.js:25012 Uncaught TypeError: this.refs.input.focus is not a function
    
    focus   @   bundle.js:25012
    handleClick @   bundle.js:25093
    ReactErrorUtils.invokeGuardedCallback   @   bundle.js:9823
    executeDispatch @   bundle.js:9607
    executeDispatchesInOrder    @   bundle.js:9630
    executeDispatchesAndRelease @   bundle.js:9062
    executeDispatchesAndReleaseTopLevel @   bundle.js:9073
    forEachAccumulated  @   bundle.js:9926
    processEventQueue   @   bundle.js:9239
    runEventQueueInBatch    @   bundle.js:16814
    handleTopLevel  @   bundle.js:16825
    handleTopLevelImpl  @   bundle.js:21235
    perform @   bundle.js:12188
    batchedUpdates  @   bundle.js:21152
    batchedUpdates  @   bundle.js:10893
    dispatchEvent   @   bundle.js:21312
    
    opened by ulfryk 9
  • Allow final layout to be customised

    Allow final layout to be customised

    Hi,

    This is a potential implementation for #47 if you consider supporting it. The idea is to allow the final layout of the input & tags to be customised as some changes are harder achieve with CSS than by changing the order of the tags.

    My use case is wanting a larger input field and the tags listed below.

    One note is that I've done this against the pre-react-0.14 code base as I'm not using react-0.14 quite yet. I think it should be easily rebased if you think it is worth including.

    From the commit message:

    We move the final layout of the tags & input into a function provided by the props with a default implementation.

    The default reproduces the current layout but the mechanism allows client code to override the final layout so that, for example, the input can appear above the tags instead of after them.

    We use function.call to pass the 'this' down to the layout function so that it can access this.props and generally be an extension of the render function.

    An alternative approach would be to have a 'flip' prop which put the input first then the tags. It would be a more focussed change. This is a more general solution but might open things up too much. Not sure. Or perhaps I'm missing a trick completely and this isn't necessary.

    Cheers, Michael

    opened by michaeljones 9
  • don't prevent tabbing when there's no input value

    don't prevent tabbing when there's no input value

    When tabbing through the interface, you get stuck in the input field, even if there's no value. It'd be nice if you could leave the input by hitting the tab key in this case.

    opened by ksmth 8
  • Set Focus To Input Field On Click Anywhere Within Control

    Set Focus To Input Field On Click Anywhere Within Control

    I made a simple change on my fork that you might want to include: make the tag control's wrapper div, the one with the react-tagsinput CSS class, "hot clickable": when user clicks anywhere within the containing div the tag's input field receives focus. A one line change since the required method already exists:

        , render: function() {
          // ... some code
          return (
            React.createElement("div", {
              className: ns + "tagsinput"
              , onClick: this.focus // <-- add this call
            }, // ... more stuff
    

    Believe this makes the thing feel "more of a piece" -- a single, seamless control.

    As always, thanks for this -- a demo with our users went exceptionally well yesterday, in no small measure thanks to this component. They didn't even end their comments with the usual "oh, but there is one more thing we need tweaked...". Bravo!

    opened by buzcarter 8
  • Restructure css and add tag themes

    Restructure css and add tag themes

    Hey @olahol

    Sort of cosmetic change, I had couple of tag stylings done so, I thought may be it would be good to put some standard tag themes - red, blue, grey etc.

    I have basically, restructured the default demo css and moved any tag styling to separate themes file (red, blue etc). I was thinking to may be use Material style input styling, probably in next commit.

    Adding a few screenshots for demo. Please review and merge, if appropriate.

    Gaurav

    grey-theme red theme

    opened by gauravtiwari 8
  • copy paste from excel

    copy paste from excel

    Hi there, great repo!!

    Is it possible to make a pasteSplit functionality that also handles copy-paste from Excel? I've tried different regex's but I can't seem to make it work.

    this is my code:

    <ReactTagsInput addOnPaste={true} pasteSplit={ data => { return data .replace(/[\n\r]/g, ' ') .split(' ') .map(d => d.trim()) }} ref="tags" value={this.state.keywords} onChange={this.handleChange} />

    and this is my dummy data from excel: image

    but doing this regex: [\n\r] splits up all of the words between whitespace. So for instance: "danish pastry", becomes "danish" and "pastry".

    any ideas? thanks! :)

    opened by MathiasLund 7
  • Allow non-strings (specifically, React Components) to be rendered within tag.

    Allow non-strings (specifically, React Components) to be rendered within tag.

    This library is great, thanks for all the work! I needed to extend it a bit so that I could drag/drop my tags once they were created.

    I came across the transform function and noticed that its contents are expected to be a string.

    I modified the library a little bit so that I could return more than just strings, like so:

    transform(tag) {
        return (
          <DraggableField tagText={tag}/>
        );
      },
    

    Which allowed me to render this:

    hover tags

    Internally, I'm thinking of storing objects instead of strings and use tag as the key and the value could be whatever: strings, react components, etc. So instead of

    valueLink.value.concat([tag]);
    

    I am thinking something like

    _.extend(valueLink.value, {tag, newTag} //newTag is the result of `format`
    

    If you think this might be an appropriate feature addition, I can spend a bit more time on it, add a test, and make a pr. Thanks.

    opened by scottccoates 7
  • Update README: Use native html datalist instead of react-autosuggest.

    Update README: Use native html datalist instead of react-autosuggest.

    react-autosuggest is unfortunately no longer maintained. The native html datalist element gives the same basic functionality with less code and zero dependencies.

    opened by jeremykay 0
  • How it works when pass empty array on start?

    How it works when pass empty array on start?

    image

    Can you check this once

    the value is empty and you writing map on it

    isn't it going to error on first run itself

    opened by naveen-iiit 0
  • How to switch the cursor among multiple tags

    How to switch the cursor among multiple tags

    How to switch the cursor among multiple tags Insert or delete by keyboard

    opened by mwei2018 0
  • Tag creation does not work on mobile

    Tag creation does not work on mobile

    I have implemented this tags input but when using it on chrome mobile it does not create tags on space. You have to blur the input to create the tag and then focus again to type new one.

    opened by NenadKaevik 1
  • dynamic width

    dynamic width

    I searched but couldn't find a solution. I don't want a width that's pre-defined. How do I change the width as the user types without hiding the text.

    opened by aningbo 0
  • Mobile devices cannot add tags - enter does not submit tags but instead moves to next form field

    Mobile devices cannot add tags - enter does not submit tags but instead moves to next form field

      <Form.Group controlId="formBasicEmail" className={styles.appFormgroup}>
          <Form.Label className={styles.appInfolabel}>{label}</Form.Label>
          <TagsInput
            className={styles.appTagsblock}
            onChange={onChange}
            onChangeInput={onChangeInput}
            inputValue={inputValue}
            value={value || []}
            maxTags={8}
            addKeys={[9, 13]}
            maxlength="16"
            {...props}
          />
          {touched && invalid && (
            <div
              className="signerror"
            >
              {error}
            </div>
          )}
        </Form.Group>
    

    Works fine on computer/browser. On mobile enter will only go to the next field and not actually submit the tags.

    opened by VexyCats 1
  • Please add the info for pasteSplit

    Please add the info for pasteSplit

    for me pasteSplit prop didn't work for so long finally i have gone through source code found out that addOnPaste prop need to be true inorder the pasteSplit to work.

    It will be good if you can add the same in the Readme, so that it will be easy for others.

    opened by madhu131313 0
  • Replace componentWillReceiveProps with componentDidUpdate to fix warnings on react 16.8

    Replace componentWillReceiveProps with componentDidUpdate to fix warnings on react 16.8

    closes #195

    Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.
        
        * Move data fetching code or side effects to componentDidUpdate.
        * If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
        * Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.
        
        Please update the following components: AutosizeInput, TagsInput
    

    More info: https://pt-br.reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops

    opened by jeancx 3
  • Tag Doesn't Come Up On Mobile and Doesn't Trim White Spaces When Using Unique

    Tag Doesn't Come Up On Mobile and Doesn't Trim White Spaces When Using Unique

    Okay, I deployed my app to my Cpanel, and I noticed that the text doesn't change into a tag when on mobile. It just takes me to the next input. Also when onlyUnique is set to true, it doesn't trim white spaces. For example: A Boy and A Boy(with white spaces) is allowed which shouldn't be so.

    opened by TravelPaddy 0
Owner
Ola
:cyclone:
Ola
Tag/word cloud component for react

Simple and extensible tag/word cloud React component.

Martin Bielik 131 Sep 5, 2021
React Google Tag Manager

This is a Javascript module to React based apps that implement Google Tag Manager. It is designed to use GTM snippet. You can easily use custom dataLayer, multiple dataLayers and additional events.

Aline Morelli 431 Sep 22, 2021