diff --git a/README.md b/README.md
index ebfedd7..226665a 100644
--- a/README.md
+++ b/README.md
@@ -105,6 +105,8 @@ ReactDOM.render(, document.getElementById('app'))
- [`tagComponent`](#tagcomponent-optional)
- [`suggestionComponent`](#suggestioncomponent-optional)
- [`inputAttributes`](#inputAttributes-optional)
+- [minTags](#minTags-optional)
+- [maxTags](#maxTags-optional)
#### id (optional)
@@ -315,6 +317,20 @@ function SuggestionComponent({ item, query }) {
An object containing additional attributes that will be applied to the text input. _Please note_ that this prop cannot overwrite existing attributes, it can only add new ones. Defaults to `{}`.
+#### minTags (optional)
+
+An integer representing the minimum number of tags that should be selected
+by the user. If the amount of selected tags is lower, the input will be
+considered to be in an invalid state.
+
+
+#### maxTags (optional)
+
+An integer representing the maximum number of tags that should be selected
+by the user. If the amount of selected tags is higher, the input will be
+considered to be in an invalid state.
+
+
### API
By adding a `ref` to any instances of this component you can access its API methods.
@@ -332,6 +348,12 @@ Removes a tag from the list of selected tags. This will trigger the delete callb
Clears the input and current query.
+#### `isValid()`
+
+Return the validation state of the input. Note that this function will return
+`true` even in the case you haven't specified `minTags` and `maxTags`.
+
+
### Styling
It is possible to customize the appearance of the component, the included styles found in `/example/styles.css` are only an example.
diff --git a/example/index.html b/example/index.html
index 449af7b..c1a9211 100644
--- a/example/index.html
+++ b/example/index.html
@@ -82,6 +82,9 @@
Country Selector
Custom tags
+
+ Validation
+
diff --git a/example/main.js b/example/main.js
index edfdf3b..f6c11f2 100644
--- a/example/main.js
+++ b/example/main.js
@@ -105,3 +105,59 @@ class CustomTags extends React.Component {
}
ReactDOM.render(, document.getElementById('demo-2'))
+
+/**
+ * Demo 3 - Validation
+ */
+class Validation extends React.Component {
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ tags: [],
+ suggestions: []
+ }
+
+ this.reactTags = React.createRef()
+ }
+
+ onDelete (i) {
+ const tags = this.state.tags.slice(0)
+ tags.splice(i, 1)
+ this.setState({ tags })
+ }
+
+ onAddition (tag) {
+ const tags = [].concat(this.state.tags, tag)
+ this.setState({ tags })
+ }
+
+ onValidate (tag) {
+ return /^[a-z]{3,12}$/i.test(tag.name);
+ }
+
+ render () {
+ return (
+ <>
+ Enter new tags meeting the requirements below:
+
+ Tags must be 3–12 characters in length and only contain the letters A-Z
+ Output:
+ {JSON.stringify(this.state.tags, null, 2)}
+ >
+ )
+ }
+}
+
+ReactDOM.render(, document.getElementById('demo-3'))
diff --git a/example/styles.css b/example/styles.css
index 46646df..5321fb3 100644
--- a/example/styles.css
+++ b/example/styles.css
@@ -36,6 +36,14 @@
cursor: text;
}
+.react-tags.react-tags__valid {
+ border: 1px solid green;
+}
+
+.react-tags.react-tags__invalid {
+ border: 1px solid red;
+}
+
.react-tags.is-focused {
border-color: #B1B1B1;
}
diff --git a/lib/ReactTags.js b/lib/ReactTags.js
index 362317c..196e047 100644
--- a/lib/ReactTags.js
+++ b/lib/ReactTags.js
@@ -17,6 +17,8 @@ const KEYS = {
const CLASS_NAMES = {
root: 'react-tags',
+ rootValid: 'react-tags__valid',
+ rootInvalid: 'react-tags__invalid',
rootFocused: 'is-focused',
selected: 'react-tags__selected',
selectedTag: 'react-tags__selected-tag',
@@ -108,7 +110,8 @@ class ReactTags extends React.Component {
this.state = {
query: '',
focused: false,
- index: -1
+ index: -1,
+ validationState: this._getValidationState()
}
this.inputEventHandlers = {
@@ -243,6 +246,35 @@ class ReactTags extends React.Component {
})
}
+ isValid () {
+ return this.state.validationState
+ }
+
+ _getValidationState () {
+ const tl = this.props.tags.length
+
+ let validationState = true
+ if (this.props.minTags && tl < this.props.minTags) {
+ validationState = false
+ }
+
+ if (this.props.maxTags && tl > this.props.maxTags) {
+ validationState = false
+ }
+
+ return validationState
+ }
+
+ componentDidUpdate (prevProps) {
+ const validationState = this._getValidationState()
+
+ if (this.state.validationState !== validationState) {
+ this.setState({
+ validationState
+ })
+ }
+ }
+
render () {
const TagComponent = this.props.tagComponent || Tag
@@ -251,6 +283,7 @@ class ReactTags extends React.Component {
const rootClasses = [classes.root]
this.state.focused && rootClasses.push(classes.rootFocused)
+ rootClasses.push(this.state.validationState ? classes.rootValid : classes.rootInvalid)
return (
@@ -329,7 +362,9 @@ ReactTags.defaultProps = {
addOnBlur: false,
tagComponent: null,
suggestionComponent: null,
- inputAttributes: {}
+ inputAttributes: {},
+ minTags: null,
+ maxTags: null
}
ReactTags.propTypes = {
@@ -365,7 +400,9 @@ ReactTags.propTypes = {
PropTypes.func,
PropTypes.element
]),
- inputAttributes: PropTypes.object
+ inputAttributes: PropTypes.object,
+ minTags: PropTypes.number,
+ maxTags: PropTypes.number
}
export default ReactTags