PVR
GitHub

Forms

Form controls, validation and the bundled form plugins, with live example pages.

2 min read
Updated June 20, 2026

Forms use Bootstrap 5 controls (.form-group + .form-control) plus several bundled plugins. Live examples: formElements.html (plain controls), formPlugins.html (plugin-enhanced fields), formValidation.html (validation), editors.html (rich text), inlineEditable.html (click-to-edit).

Basic controls — formElements.html

↗ View live demo

<!-- Text input (the .required class marks the label) -->
<div class="form-group mb-3">
  <label class="required" for="textInput">Full name</label>
  <input class="form-control" id="textInput" type="text" placeholder="Enter text">
</div>
 
<!-- Email / password -->
<div class="form-group mb-3">
  <label for="emailInput">Email</label>
  <input class="form-control" id="emailInput" type="email" placeholder="Enter email">
</div>
 
<!-- Select -->
<div class="form-group mb-3">
  <label for="selectSingle">Single select</label>
  <select class="form-control" id="selectSingle">
    <option>Option 1</option>
    <option>Option 2</option>
  </select>
</div>
 
<!-- Textarea -->
<div class="form-group mb-3">
  <label for="textareaBasic">Message</label>
  <textarea class="form-control" id="textareaBasic" rows="3"></textarea>
</div>
 
<!-- Native date / datetime -->
<div class="form-group mb-0">
  <label for="dateInput">Date</label>
  <input class="form-control" id="dateInput" type="date">
</div>

Checkboxes / radios:

<!-- Bootstrap standard -->
<div class="form-check mb-2">
  <input class="form-check-input" id="check1" type="checkbox">
  <label class="form-check-label" for="check1">Default checkbox</label>
</div>
 
<!-- Kit's styled checkbox -->
<label class="custom-checkbox d-block mb-2">
  <input type="checkbox" checked>
  <span class="checkmark"></span>
  <span class="label-text">Styled checkbox</span>
</label>

Form control overrides (sizing, focus styles, etc.) are baked into style.css. Just use .form-control, .form-group, .form-check and they'll match the theme.

Plugin-enhanced fields — formPlugins.html

↗ View live demo

Each plugin field is a normal input that a class/attribute activates. The page script (assets/js/pages/ui/formPlugins.js) initializes them. Markup + the init call:

Select2

<select class="form-control select2-basic"> … </select>
<select class="form-control select2-multiple"> … </select>
<select class="form-control select2-placeholder"><option></option> … </select>
<select class="form-control select2-tags"> … </select>
$('.select2-basic').select2({ width: '100%' });
$('.select2-multiple').select2({ width: '100%', placeholder: 'Select options', closeOnSelect: false });
$('.select2-placeholder').select2({ width: '100%', placeholder: 'Select a fruit', allowClear: true });
$('.select2-tags').select2({ width: '100%', tags: true, tokenSeparators: [',', ' '] });

Date range / datetime / time pickers

<input class="form-control daterangepicker-input" type="text" placeholder="Select date range">
<input class="form-control datetimepicker" type="text" placeholder="Select date and time">
<input class="form-control timepicker" type="text" placeholder="Select time">
$('#basicDateRange').daterangepicker({ opens: 'left', locale: { format: 'DD/MM/YYYY' } });
$('#singleDatePicker').daterangepicker({ singleDatePicker: true, showDropdowns: true });
$('#dateTimeRangePicker').daterangepicker({ timePicker: true, timePicker24Hour: true, timePickerIncrement: 15 });

TouchSpin (number stepper)

<input class="touchspin-default" type="text" value="50">
<input class="touchspin-decimal" type="text" value="5.0">
<input class="touchspin-prefix" type="text" value="100">
$('.touchspin-default').TouchSpin({ min: 0, max: 100, buttondown_class: 'btn btn-outline-secondary', buttonup_class: 'btn btn-outline-secondary' });
$('.touchspin-decimal').TouchSpin({ min: 0, max: 10, step: 0.1, decimals: 1 });
$('.touchspin-prefix').TouchSpin({ min: 0, max: 1000, prefix: '$' });

Ion range slider

<input class="range-slider" type="text">
<input class="range-slider-double" type="text">
<input class="range-slider-currency" type="text">
$('.range-slider').ionRangeSlider({ min: 0, max: 100, from: 50, skin: 'round' });
$('.range-slider-double').ionRangeSlider({ type: 'double', min: 0, max: 100, from: 25, to: 75 });
$('.range-slider-currency').ionRangeSlider({ min: 0, max: 1000, from: 500, prefix: '$', grid: true });

Cleave.js (input masking)

<input class="form-control cleave-creditcard" type="text" placeholder="0000 0000 0000 0000">
<input class="form-control cleave-date-dmy"   type="text" placeholder="DD/MM/YYYY">
<input class="form-control cleave-phone"      type="text" placeholder="(000) 000-0000">
<input class="form-control cleave-currency"   type="text" placeholder="0.00">

Color picker (Coloris)

<input type="text" data-coloris placeholder="Pick a color">
Coloris({ el: '[data-coloris]', theme: 'default', themeMode: 'auto', alpha: true, clearButton: true });

File upload (Dropzone)

<form id="dropzoneForm" class="dropzone" enctype="multipart/form-data"></form>
new Dropzone('#dropzoneForm', { url: '/upload', maxFiles: 5, maxFilesize: 2, acceptedFiles: 'image/*,.pdf', addRemoveLinks: true });

Validation — formValidation.html

↗ View live demo

Forms use jQuery Validate. Give inputs a name, then call .validate() with rules and messages. The kit's pages use Bootstrap's is-invalid / is-valid classes and place errors as .invalid-feedback inside the .form-group:

<form id="basicValidationForm">
  <div class="form-group mb-3">
    <label class="required" for="fullName">Full name</label>
    <input class="form-control" id="fullName" name="fullName" type="text">
  </div>
  <div class="form-group mb-3">
    <label class="required" for="basicEmail">Email</label>
    <input class="form-control" id="basicEmail" name="email" type="email">
  </div>
  <div class="form-group mb-3">
    <label class="required" for="basicPassword">Password</label>
    <input class="form-control" id="basicPassword" name="password" type="password">
  </div>
  <div class="form-group mb-3">
    <label class="required" for="confirmPass">Confirm password</label>
    <input class="form-control" id="confirmPass" name="confirmPassword" type="password">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>
$('#basicValidationForm').validate({
    rules: {
        fullName:        { required: true, minlength: 3 },
        email:           { required: true, email: true },
        password:        { required: true, minlength: 6 },
        confirmPassword: { required: true, equalTo: '#basicPassword' }
    },
    messages: {
        fullName: { required: 'Please enter your full name', minlength: 'Name must be at least 3 characters' },
        email:    { required: 'Please enter your email',     email: 'Please enter a valid email address' }
    },
    errorClass: 'is-invalid',
    validClass: 'is-valid',
    errorPlacement: function (error, element) {
        error.addClass('invalid-feedback');
        element.closest('.form-group').append(error);
    },
    highlight:   function (el) { $(el).addClass('is-invalid').removeClass('is-valid'); },
    unhighlight: function (el) { $(el).removeClass('is-invalid').addClass('is-valid'); },
    submitHandler: function (form) { /* submit here */ return false; }
});

Common rules used in the demos: required, minlength, email, url, equalTo, min/max, digits, number, creditcard, and custom pattern regexes. app.js also exposes an app.validation helper with shared defaults — see 08 — JavaScript.

Rich-text editors — editors.html

↗ View live demo

<!-- Summernote -->
<div id="summernoteEditor"></div>
 
<!-- Quill -->
<div id="quillEditor"></div>
$('#summernoteEditor').summernote({ height: 400 });
var quill = new Quill('#quillEditor', { theme: 'snow', placeholder: 'Compose…' });

CKEditor 5, Quill, Summernote and CodeMirror are all bundled under assets/plugins/.

Inline editing — inlineEditable.html

↗ View live demo

Make any element click-to-edit with data-editable attributes:

<a href="#" data-editable="text"     data-editable-value="john_doe">john_doe</a>
<a href="#" data-editable="select"   data-editable-value="active"
   data-editable-source='[{"value":"active","text":"Active"},{"value":"inactive","text":"Inactive"}]'>Active</a>
<a href="#" data-editable="textarea" data-editable-value="Some notes…">Some notes…</a>
<a href="#" data-editable="date"     data-editable-value="1990-05-15">1990-05-15</a>

Optional data-editable-placement="top|bottom|left|right" controls the popup position. The behavior is wired up by app.js (app.inlineEditable).

Was this page helpful?