npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-material-ui-form

v1.1.7

Published

State and validation management for Material-UI form components

Downloads

108

Readme

react-material-ui-form

MIT npm BuildStatus Downloads SourceRank

  1. About
  2. Setup
  3. Props
  4. Examples
  5. Contributing
  6. License

About

react-material-ui-form is a React wrapper for Material-UI form components. Simply replace the <form> element with <MaterialUIForm> to get out-of-the-box state and validation support as-is. There's no need to use any other components, alter your form's nesting structure, or write onChange handlers.

Validation is done with validator.js but you can extend/customize validation messages, validators, and use your own validation logic too. Steppers, dynamic array fields and custom components are also supported.

use and requirements

  • requires React 16.3.0 or newer
  • supports official and unofficial Material-UI fields (other input elements are rendered without state/validation support)
  • every input field must have value and name props
  • every input field should NOT have onChange and onBlur props (unless you need custom field-specific logic)
  • add a data-validators prop to any input field (or FormControl / FormControlLabel) to specify validation rules

extra validators

react-material-ui-form extends validator.js validators with the following validators:

  • isAlias /^[a-zA-Z0-9-_\.]*$/i
  • isDate
  • isNumber /^([,.\d]+)$/
  • isRequired value.length !== 0
  • isSerial /^([-\s\da-zA-Z]+)$/
  • isSize value >= min && value <= max
  • isTime
  • isLength(min,max) [{ isLength: { min: 2, max: 50 } }]

Supported field components

  • TextField
  • TextField { select }
  • TextField { multiline, textarea }
  • Checkbox
  • RadioGroup
  • Radio
  • FormControlLabel (control prop)
  • FormLabel
  • InputLabel

Note

Currently this package will support only till Material-UI v3

Setup

install

npm install --save react-material-ui-form

demo

  1. $ git clone https://github.com/voletiswaroop/react-material-ui-form.git
  2. $ cd react-material-ui-form
  3. $ npm install && npm run dev

Props

Form props (optional):

Prop | Description | Default ------------------------------| --------------------------|------------ [class] [string] | Sets className attribute to the form | [id] [string] | Sets id attribute to the form | [name] [string] | Sets name attribute to the form | [action] [string] | Sets action attribute to the form | activeStep [number] | Use together with onFieldValidation for better Stepper support | autoComplete [string] | Sets form autoComplete prop. Accepts one of ["on", "off"] | "off" disableSubmitButtonOnError [boolean] | Disables submit button if any errors exist | true onFieldValidation [func] | Returns @field and @errorSteps (if activeStep prop is provided) on field validation | onSubmit [func] | Returns @values and @pristineValues on form submission | onValuesChange [func] | Returns @values and @pristineValues on field value change | validation [object] | Object specifing validation config options (prefixed below with ↳) | ↳ messageMap [object] | A key-value list where the key is the validator name and the value is the error message. Is exposed as a react-material-ui-form export parameter | objectmessageKeyPrefix [string] | Optional prefix to apply to all messageMap keys. If specified, field validator names will automatically be appended the prefix | "" ↳ requiredValidatorName [boolean, string] | Specifies the validator name and matching messegeMap key for required fields. To disable and rely on the native required field prop, set to false | "isRequired" ↳ validate [func] | Overrides the internal validate method. Receives the following parameters: @fieldValue, @fieldValidators, and @...rest (where @...rest is the validation prop object) | funcvalidators [object] | Defaults to an extended validator.js object. Is exposed as a react-material-ui-form export parameter | objectvalidateInputOnBlur [boolean] | Makes text input validations happen on blur instead of on change | false validations [object] | Validations to pass to the form (i.e. from the server). Should be an object with keys representing field name props and values as arrays of field error messages. The first error message will be displayed per field |

Field props:

Prop | Description | Required ------------------------------| --------------------------|------------ value [any] | The value of the field. If empty set an empty string | Yes name [string] | The name of the field | Yes data-validators [string, array[object]] | Validators to apply to the field. Multiple validator names can be specified with a comma-delimited string |
onBlur [func] | A custom handler that will be called after the field's onBlur event. Provides @value/checked, @field and @event parameters | onChange [func] | A custom handler that will be called after the field's onChange event. Provides @value/checked, @field and @event parameters |

Other props:

Prop | Value | Description
-------------------------| ------------------|------------------------ deletefieldrow [string] | Field name prop up to and including the row index (i.e. rooms[2]) | Add to button components that use onClick to remove any array field rows

Material-UI form production build classnames conflict issues

To avoid default material-ui production build classnames conflict issues include your entire form inside Example: Nested fields

Examples

Nested fields:

import MaterialUIForm from 'react-material-ui-form'
import JssProvider from 'react-jss/lib/JssProvider';

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  customInputHandler = (value, { name }, event) => {
    // the form will update the field as usual, and then call this handler
    // if you want to have complete control of the field, change the "value" prop to "defaultValue"
  }

  customToggleHandler = (checked, { name, value }, event) => {
    // the form will update the field as usual, and then call this handler
    // if you want to have complete control of the field, change the "value" prop to "defaultValue"
  }

  render() {
    return (
      <JssProvider>
        <MaterialUIForm onSubmit={this.submit}>
          <TextField label="Name" type="text" name="name" value="" data-validators="isRequired,isAlpha" onChange={this.customInputHandler} />
          <fieldset>
            <FormControl>
                {/* form label is required here to perform default validations */}
                <FormLabel component="legend">I love React material UI form</FormLabel>
                <FormGroup value=''>
                  <FormControlLabel control={<Checkbox value='yes' />}
                    label='I love React material UI form'/>
                </FormGroup>
              </FormControl>

            <FormControl required>
              <InputLabel>Age</InputLabel>
              <Select value="" name="age">
                <MenuItem value=""><em>Please select your age ...</em></MenuItem>
                <MenuItem value={10}>Teens</MenuItem>
                <MenuItem value={20}>Twenties</MenuItem>
                <MenuItem value={30}>Thirties</MenuItem>
                <MenuItem value="40+">Fourties +</MenuItem>
              </Select>
              <FormHelperText>Some important helper text</FormHelperText>
            </FormControl> 
          </fieldset>
          
          <FormControl>
            <FormLabel component="legend">Gender</FormLabel>
            <RadioGroup aria-label="Gender" name="gender"  value="male">
              <FormControlLabel value="female" control={<Radio />} label="Female" />
              <FormControlLabel value="male" control={<Radio />} label="Male" /> 
            </RadioGroup>
          </FormControl>
          
          <Button variant="raised" type="reset">Reset</Button>
          <Button variant="raised" type="submit">Submit</Button>
        </MaterialUIForm>
      </JssProvider>
    )
  }
}

Custom validators:

import Form, { messageMap, validators } from 'react-material-ui-form/dist/validation/index';
 

validators.isBorat = value => value === 'borat'
const customMessageMap = Object.assign(messageMap, {
  isBorat: 'NAAAAAT! You can only write "borat" lol',
})

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validation={{ messageMap: customMessageMap, validators, }}>
        <TextField label="Write anything..." type="text" name="trickster" value="" helperText="this is not a trick" data-validators="isBorat" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Custom validation messages:

const customFormMsg = Object.assign(messageMap, { 
  isEmail: 'Please enter a valid email address',  
  isLength:'Must be 2-50 characters', 
})
class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }
render() {
  return (
    <MaterialUIForm onSubmit={this.submit} validation={{ messageMap: customFormMsg}}>
      <TextField label="Name" type="text" name="FirstName" value="Name" data-validators="isLength" />
      <TextField label="Email" type="text" name="Email" value="[email protected]" data-validators="isRequired,isEmail" />
      <Button variant="raised" type="submit">Submit</Button>
    </MaterialUIForm>
    )
  }
}

Custom validation logic:

import MaterialUIForm from 'react-material-ui-form'
 

function validate(value, fieldValidators, options) {
  const fieldValidations = []
  fieldValidators.forEach((validator) => {
    const validation = {
      code: String(validator),
      message: 'its invalid so maybe try harder...',
    }
    if (_.has(options, 'genericMessage')) {
      validation.message = options.genericMessage
    }
    fieldValidations.push(validation)
  })
  return fieldValidations
}

const validationOptions = {
  genericMessage: 'yeah... *tisk*',
}

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validation={{ requiredValidatorName: false, validate, ...validationOptions, }}>
        <TextField label="Whatever you write isn't gonna be good enough" type="text" name="test" value="" data-validators="whatever - our custom validator will ignore this" required />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Server validations:

import MaterialUIForm from 'react-material-ui-form'
 

const mockServerValidations = {
  name: [{ code: 'isInvalid', message: 'such invalid...' }],
}

class MyForm extends React.Component {
  state = {
    mockServerValidations,
  }

  componentDidMount() {
    let validations = {
      name: [{ message: 'such WOOOOOOOOOW...' }],
    }

    setTimeout(() => {
      this.setState({ mockServerValidations: validations })
    }, 1500)

    setTimeout(() => {
      validations = {
        name: [{ message: 'so still haven\'t watched Italian Spiderman?' }],
      }
      this.setState({ mockServerValidations: validations })
    }, 3000)
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} validations={this.state.mockServerValidations}>
        <TextField label="Name" type="text" name="name" value="doge" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Form autoComplete and "on error" submission:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm autoComplete="on" disableSubmitButtonOnError={false} onSubmit={this.submit}>
        <TextField label="Name" type="text" name="name" value="doge" data-validators="isInt" />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Getting form values on field update:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  handleValuesChange = (values, pristineValues) => {
    // get all values and pristineValues when any field updates
  }

  handleFieldValidations = (field) => {
    // get field object when its validation status updates
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  render() {
    return (
      <MaterialUIForm onSubmit={this.submit} onValuesChange={this.handleValuesChange} onFieldValidation={this.handleFieldValidations}>
        <TextField label="Name" name="name" value="doge" required />

        <Button variant="raised" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Stepper:

import Stepper, { Step, StepLabel } from 'material-ui/Stepper'
import MaterialUIForm from 'react-material-ui-form'
 

function getSteps() {
  return [
    'Step 1',
    'Step 2',
  ]
}

class MyForm extends React.Component {
  state = {
    activeStep: 0,
    errorSteps: [],
  }

  clickNext = () => {
    this.setState({
      activeStep: this.state.activeStep + 1,
    })
  }

  clickBack = () => {
    this.setState({
      activeStep: this.state.activeStep - 1,
    })
  }

  submit = (values, pristineValues) => {
    // get all values and pristineValues on form submission
  }

  updateErrorSteps = (field, errorSteps) => {
    this.setState({ errorSteps })
  }

  render() {
    const steps = getSteps()
    const { activeStep } = this.state

    return (
      <div>
        <Stepper activeStep={activeStep} alternativeLabel>
          {steps.map((label, i) => (
            <Step key={label}>
              <StepLabel error={errorSteps.includes(i)}>
                {label}
              </StepLabel>
            </Step>
          ))}
        </Stepper>

        <MaterialUIForm activeStep={activeStep} onFieldValidation={this.updateErrorSteps} onSubmit={this.submit}>
          {activeStep === 0 &&
            <React.Fragment>
              <TextField label="Name" name="name" value="" required />
              <Button variant="raised" onClick={this.clickNext}>Next</Button>
            </React.Fragment>
          }

          {activeStep === 1 &&
            <React.Fragment>
              <TextField label="Address" name="address" value="" required />
              <Button variant="raised" onClick={this.clickBack}>Back</Button>
              <Button variant="raised" type="submit">Submit</Button>
            </React.Fragment>
          }
        </MaterialUIForm>
      </div>
    )
  }
}

Dynamic array fields (notice the deletefieldrow prop on the "Remove Row" button):

import MaterialUIForm from 'react-material-ui-form'
import formData from 'form-data-to-object'
 

class MyForm extends React.Component {
  state = {
    rows: [{ _id: _.uniqueId() }],
    onSubmitValues: null,
  }

  addRow = () => {
    const { rows } = this.state
    rows.push({ _id: _.uniqueId() })
    this.setState({ rows })
  }

  removeRow = (index) => {
    const { rows } = this.state
    if (rows.length > 1) {
      rows.splice(index, 1)
      this.setState({ rows })
    }
  }

  submit = (values, pristineValues) => {
    // you can parse values to turn:
    // rows[0][label]: "label"
    // into:
    // rows: [{ label: "label" }]
    const parsedValues = formData.toObj(values)
  }

  render() {
    const steps = getSteps()

    return (
      <MaterialUIForm onSubmit={this.submit}>
        {this.state.rows.map((row, i) => (
          <Fragment key={row._id}>
            <TextField label="Label" name={`rows[${i}][label]`} value="" required />
            <TextField label="Value" name={`rows[${i}][value]`} value="" />
            { this.state.rows.length > 1 &&
              <Button onClick={()=> this.removeRow(i)} deletefieldrow={`rows[${i}]`}>Remove Row</Button>
            }
          </Fragment>
        ))}
        
        <Button variant="raised" onClick={this.addRow}>Add row</Button>
        <Button variant="raised" color="primary" type="submit">Submit</Button>
      </MaterialUIForm>
    )
  }
}

Custom components with custom handlers:

import MaterialUIForm from 'react-material-ui-form'
 

class MyForm extends React.Component {
  uploadFile = (event) => {
    console.log(event.target.files)
  }

  render() {
    return (
      <div>
        <MaterialUIForm>
          {'Upload file: '}
          <input accept="image/*" style={{ display: 'none' }} id="raised-button-file" multiple type="file" onChange={this.uploadFile} />
          <label htmlFor="raised-button-file">
            <Button variant="raised" component="span">Upload</Button>
          </label>
        </MaterialUIForm>
      </div>
    )
  }
}

Contributing

This is a new project and contributions are welcome so feel free to open an issue or fork and create a pull request. Collaborators are also welcome - please send an email to [email protected].

License

This project is licensed under the terms of the MIT license.