react-nice-inputs

This component gallery help to create easy inputs and input groups on your forms. This approaches to a simpler solution when you need to design forms, input components that are declarative and easy to use.

Usage no npm install needed!

<script type="module">
  import reactNiceInputs from 'https://cdn.skypack.dev/react-nice-inputs';
</script>

README

react-nice-inputs

This component gallery help to create easy inputs and input groups on your forms. This approaches to a simpler solution when you need to design forms, input components that are declarative and easy to use.

Installing React Nice Inputs

npm i react-nice-inputs

Et voila, now you need to import the library to your project by:

import { Input } from 'react-nice-inputs'

Using a component

Ok so now you are ready to use them lets see the most simple one: an input

<Input type="text" // type is required
  name="some-input" // is required
  classList={ [ 'col', 'sm-12', 'md-4' ] } // is required
  onChange={ (value) => { this.setState({ yourParentComponentState: value }) } } // is required
  attrs={ { placeholder: 'enter a value' } }
  isValid="true"
/>

This renders as:

<input type="text" name="some-input" id="some-input" class="input col sm-12 md-4 is-valid" placeholder="enter a value">

And your browser input:

alt text

I used a custom css for my input in this example.

Test the library yourself here

The class input is a utility class you can use to paint and custom your inputs, col, sm-12 and md-4 were the class list you sent as prop, is-valid was added by the component lib by the prop isValid, this helps you to style the input as you need if the input is valid; if not then you need to send the isInvalid prop as true.

What about the input value itself? For this purpose you can define a function that handles the value that the Input component will return to you. How so? Check the prop onChange; it does send a function and inside sets an attribute for the parent state. The Input component will return you:

  • The input value
  • The input name
  • The element for further usage
  • The Momentjs object (for dropdowndates component only) All of them in that specific order.

The prop attrs helps you to send other attributes to the input that you may find useful, like in my example: a placeholder.

The Primitive Components

We saw how to create a simple text input, there are other primitive components along with the Input component

Select

The select component is still simple, shares most of the input component props but since it is a collection of options, it needs a extra prop called "options". Check the props list below.

{
  name: 'some-components', // is required
  classList: [ 'col', 'sm-12', 'md-4' ], // is required
  attrs: {
    ...
  },
  onChange: (value) => { // is required
    this.validateUserSelection(value);
  },
  options: [ // is required
    { label: 'Input Component', value: 'input' },
    { label: 'Select Component', value: 'select' },
    { label: 'Checkbox / Radio Component', value: 'inputgroup' }
  ],
  defaultText: 'Select a input...',
  isValid: true,
  isInvalid: false,
  value: ''
}

Again the classList is an array that you can define and change and will impact the select itself, on change is your function to handle the input change, the options props is an array of object with the label and value properties and these becomes the select options, the default text is the option empty and the text for it can be customizable, is valid and invalid props are self explanatory and the value prop helps to accept a default value for the input.

So the rendered select would look like:

alt text

alt text

InputGroup

The input group component helps to render a checkbox or radio button group. Again it shares the same component props as the Input and Select. Lets see its props:

{
  type: 'checkbox', // is required
  name: 'favorite-pets', // is required
  classList: [ 'col', 'sm-12', 'md-4' ], // is required
  onChange: (value) => { // is required
    this.validateUserChoices(value);
  },
  options: [ // is required
    { label: 'Dogs 🐺', value: 'dogs' },
    { label: 'Parrots 🐦', value: 'parrots' },
    { label: 'Cats 😹', value: 'cats' },
    { label: 'Dinosaurs 🦖', value: 'dinos', attrs: { disabled: true } }
  ],
  isValid: true,
  isInvalid: false,
  value: [ 'dogs', 'parrots' ]
}

The type prop can be either checkbox or radio, by now you know the classList prop, the onChange prop, options can have label and value properties and in addition to a attrs property to define custom attributes for each option (do not precheck here, use the value prop). The value prop: this is an array as you can see of values that correspond to the options values, you can define which values can be prepopulated; now, do note that in the case of the radio buttons if you send more than one value it will always pick the latest from the array of values. From the example above dogs and parrots will be checked, if type is radio then parrots will be checked.

So the rendered checkboxes/radios would look like:

alt text

Autocomplete

The autocomplete input is a textbox that displays a list of options that the user can select from, the option list is filtered as the user types in in the textbox. Let us check the props:

{
  name: 'fav-animal', // is required
  classList: [ 'col', 'sm-12', 'md-4' ], // is required
  attrs: { 'data-customid': 'someid' },
  onChange: (value) => { // is required
    this.validateUserChoice(value);
  },
  dataList: [ // is required
    { label: 'Dogs 🐺', value: 'dogs' },
    { label: 'Parrots 🐦', value: 'parrots' },
    { label: 'Cats 😹', value: 'cats' },
    { label: 'Chickens 🐓', value: 'chickens' },
    { label: 'Pigs 🐷', value: 'pigs' },
    { label: 'Mice 🐭', value: 'mice' },
    { label: 'Ant Colony 🐜', value: 'ants' },
    { label: 'Fishes 🐠', value: 'fishes' },
    { label: 'Dinosaurs 🦖', value: 'dinos' }
  ],
  isValid: true,
  isInvalid: false,
  value: ''
}

The example above shows a list of animals, if you type in something then the list narrows down to the matches in the list as you type in. You know the classic props: classList, attrs, onChange, isValid, isInvalid, value. This component highlight is the dataList prop, it holds the same verbosity as the options prop for the input group, it will build the list based on this array of objects. Your autocomplete would look like:

alt text

Label, Icon and Feedback

The label, icon and the feedback components are a simple primitive components that as you might already guessed display text along with your inputs in the case a FormGroup component is too restrictive or in a case where your Label can not be semantically next to your input. To create a label you need to do the following:

<Label htmlFor="" classList={ [ 'col', 'sm-12' ] }>Enter your first name: <sup>*</sup></Label>

an Icon

<Icon classList={ [ 'fa', 'fa-facebook' ] } />

a Feedback

<Feedback>Life finds a way!</Feedback>

Labels and Icons take classList props while Feedback do not, this way you keep a simplistic approach on rendering feedbacks, is just a message under your inputs. Labels can be styled by selecting: control-label class and Feedbacks can be accessed by the form-feedback. The Label component takes a htmlFor prop to define what input id target to when clicked.

Second Level Components

These components are built using the primitives described above, they work together as they are encapsulated into a higher level wrapper.

FormGroup

This component is constructed with the following structure:

<Label />
<Icon />
<Input /> || <Select /> || <InputGroup /> || <Autocomplete />
<Feedback>

This way the way this works is by sending the appropiate props. Let's see:

{
  type: 'select', // is required
  name: 'countries', // is required
  classList: [ 'some', 'classes', 'for', 'input' ], // is required
  onChange: (value) => { // is required
    this.saveCountry(value);
  },
  feedback: 'This field is required.', // not required :P
  icon: [ 'fa', 'fa-edit' ],
  isValid: true,
  isInvalid: false,
  label: 'Your Country *',
  defaultText: 'Pick a country:',
  dataList, options: [
    { label: 'Guatemala 🇬🇹', id: 502 },
    { label: 'El Salvador 🇸🇻', id: 503 },
    { label: 'Honduras 🇭🇳', id: 504 },
    { label: 'Nicaragua 🇳🇮', id: 505 },
    { label: 'Costa Rica 🇨🇷', id: 506 }
  ],
  boxClassList: [ 'col', 'sm-12', 'md-4' ],
  listElement: <Future release />, // this will help to style the list elements on the autocomplete list.
  value: ''
}

The type prop can take any of the listed input primitive types: input, select, checkbox, radio, autocomplete. You know the old classList, onChange, isValid, isInvalid, attrs. The icon and feedback props help to assign an icon for the group and if needed a feedback, this is specially helpful if you are validating the group and want to send a custom message. The label prop will also create a label for the group, here you don't need to send the htmlFor. When you are creating a select group a checkbox or radio group, you want to send the options props, but if you have defined type to autocomplete you will need to send the dataList prop. There is the defaultText prop for selects as well. The boxClassList is a special prop that helps you to define boxing classes if you are using grid systems such as bootstrap or flexbox, these classes will be applied to the group wrapper. The value prop helps to define a default value for the group.

Your input group would render like:

alt text

Third Level Components

These components are created based on the second level components.

DropDownDates

This component will render three select inputs each for month, day and year. Some design like this idea when there is a native datepicker(ugly) or other solutions(nope! not jquery datepicker) to display and allow users to pick dates; in the opinion of this humble dev drop down dates should be the last resort option to pick dates, but I know we live in an imperfect universe there will be cases when there is no option, so, the DropDownDates component will come handy. Let's see the prop list:

{
  name: 'profile-dob', // is required
  classList: [ 'some', 'classes', 'for', 'input' ], // is required
  attrs: {
    ...
  },
  onChange: (value, name, e, m) => { // is required
    // handle the input properties
  },
  defaultTextM: 'Pick an option...',
  defaultTextD: 'Pick an option...',
  defaultTextY: 'Pick an option...',
  labelM: 'Month:',
  labelD: 'Day:',
  labelY: 'Year:',
  label: 'Provide your date of birth *',
  feedback: 'This field is required.',
  isValid: true,
  isInvalid: false,
  mmmm: true,
  format: 'MM/DD/YY',
  minDate: '3/26/85',
  maxDate: '3/31/18',
  value: '',
  mmClassList: [ 'col', 'sm-12', 'md-8' ],
  ddClassList: [ 'col', 'sm-12', 'md-4' ],
  yyyyClassList: [ 'col', 'sm-12' ]
}

There are a quite a few props as you can see, best go over them now: defaultTexts can be assigned to Month group, Day group and Year group. There is an upper level label to correspond to the entire drop down date component, but this is not required; neither are the label above each dropdown however you can custom these as well, check the labelM, labelD and labelY props. The feedback prop is associated as the label above to the entire drop down date component, not to a single select. The mmmm prop is yummy, it's a boolean you send if you need your months names to be displayed as words, else it will be rendered as just numbers. The format prop stablishes the format this component will use, and send back in the onChange function for you, it also help to validate other props format, if they don't match, then a message is displayed in the browser console. Keep in mind that I used momentjs so you can use as much formats as momentjs can support. The default format is: MM-DD-YYYY. The minDate and maxDate props determines the date ranges you can pick on the selects, this is tricky because if the user has not yet picked the entire 3 chunks of the date, you don't know yet how to validate the ranges, however, if the user starts selecting the month or year the component will at least have an initial parameter to validate. Given the date ranges on the example above, say the user start to pick the month, the twelve months of the year will be available at this point, but if the user picks march, because we still dont know what year from 1985 to 2018 is the user gonna pick the available days starts from first to 31th, if the user however selects 1985 the dates options on the day select are shortened from 26th up to 31st, then the user needs to repick the date; months available now are only from march to december. Same scenario if the user picks or changes to 2018 as year, dates get rerendered from first to 31th. This is pretty much why dropdown dates are not a good idea generally, but this component will do it's job.

Example A - The min date behavior

alt text

Example B - The max date behavior

alt text

TL:DR version: options in the month and day are rebuilt depending on the year selected by the user within the date range.

The default values for minDate and maxDate props are January 1st, 1975 and December 31th current year. The box classLists for the month, day and year group can be also customized in case you are using grid systems and need to redimension each individually. The onChange prop for dropdowndates is special one because it returns yet four parameters, while others return just three, the fourth parameter in this component is the momentjs object built within the component for your further usage so you don't need to reimport momentjs to your project, you can reuse this param and work with it as you see fit.

The final input group would be rendered like:

alt text

Final Notes

So thats REACT-NICE-INPUTS component library, however there are more components to come:

  • password input with reveal hide feature
  • grecaptcha input
  • form model context
  • custom item on autocomplete options list
  • input validation based on custom functions or rules

This repo can be found on: https://gitlab.com/wbarahona/react-nice-inputs feel free to fork it and enhance it, any pull request for bug fixing would mean a lot to me. Follow me at:

Thanks for using and spread the word.

HAPPY CODING </>