JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/recompose/build/Recompose.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Babel + JSX
const { compose, withState, withHandlers, mapProps } = Recompose
const { omit } = _
const forbidCharacters = forbiddenCharsRegexp =>
withHandlers({
onChange: props => event => {
if (props.onChange) {
const value = event.target.value
const cleanValue = value.replace(forbiddenCharsRegexp, '')
const newEvent = {
...event,
target: { ...event.target, value: cleanValue }
}
props.onChange(newEvent)
}
}
})
const formatInputValue = ({ formatValue, parseValue }) =>
compose(
withState('inputValue', 'setInputValue', props => formatValue(props.value)),
withHandlers({
onChange: props => event => {
props.setInputValue(event.target.value)
},
onBlur: props => event => {
const parsedValue = parseValue(props.inputValue)
const formattedValue = formatValue(parsedValue)
props.setInputValue(formattedValue)
const newEvent = {
...event,
target: { ...event.target, value: parsedValue }
}
if (props.onChange) {
props.onChange(newEvent)
}
if (props.onBlur) {
props.onBlur(newEvent)
}
}
}),
mapProps(({ inputValue, ...otherProps }) => ({
...omit(otherProps, ['inputValue', 'setInputValue']),
value: inputValue
}))
)
const BaseInput = props => <input {...props} />
const PhoneNumberInput = compose(
formatInputValue({
formatValue: value => {
return value.replace(/^(\d{3})(\d{3})(\d{4})$/, '($1) $2-$3')
},
parseValue: formattedValue => {
return formattedValue.replace(/[^\d]/g, '').slice(0, 10)
}
}),
forbidCharacters(/[^\d\s\-()]/g)
)(BaseInput)
class App extends React.Component {
constructor(props) {
super(props)
this.state = { phoneNumber: '' }
}
onChange = event => {
this.setState({ phoneNumber: event.target.value })
}
render() {
return (
<div>
<PhoneNumberInput
...