Compare commits
3 Commits
v6-rm-dist
...
gs-forms
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a4a3e9fe1 | |||
| 27e5375912 | |||
| aa6a1ece56 |
@@ -34,27 +34,27 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.bundle.js",
|
||||
"maxSize": "43.25 kB"
|
||||
"maxSize": "44.55 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.bundle.min.js",
|
||||
"maxSize": "22.75 kB"
|
||||
"maxSize": "23.75 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.esm.js",
|
||||
"maxSize": "28.0 kB"
|
||||
"maxSize": "29.75 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.esm.min.js",
|
||||
"maxSize": "18.5 kB"
|
||||
"maxSize": "19.25 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.js",
|
||||
"maxSize": "28.75 kB"
|
||||
"maxSize": "30.5 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.min.js",
|
||||
"maxSize": "16.25 kB"
|
||||
"maxSize": "16.75 kB"
|
||||
}
|
||||
],
|
||||
"ci": {
|
||||
|
||||
@@ -10,6 +10,7 @@ export { default as Button } from './src/button'
|
||||
export { default as Carousel } from './src/carousel'
|
||||
export { default as Collapse } from './src/collapse'
|
||||
export { default as Dropdown } from './src/dropdown'
|
||||
export { default as Form } from './src/forms/form'
|
||||
export { default as Modal } from './src/modal'
|
||||
export { default as Offcanvas } from './src/offcanvas'
|
||||
export { default as Popover } from './src/popover'
|
||||
|
||||
@@ -9,6 +9,7 @@ import Alert from './src/alert'
|
||||
import Button from './src/button'
|
||||
import Carousel from './src/carousel'
|
||||
import Collapse from './src/collapse'
|
||||
import Form from './src/forms/form'
|
||||
import Dropdown from './src/dropdown'
|
||||
import Modal from './src/modal'
|
||||
import Offcanvas from './src/offcanvas'
|
||||
@@ -23,6 +24,7 @@ export default {
|
||||
Button,
|
||||
Carousel,
|
||||
Collapse,
|
||||
Form,
|
||||
Dropdown,
|
||||
Modal,
|
||||
Offcanvas,
|
||||
|
||||
@@ -36,6 +36,10 @@ class BaseComponent extends Config {
|
||||
}
|
||||
|
||||
// Public
|
||||
getElement() {
|
||||
return this._element
|
||||
}
|
||||
|
||||
dispose() {
|
||||
Data.remove(this._element, this.constructor.DATA_KEY)
|
||||
EventHandler.off(this._element, this.constructor.EVENT_KEY)
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap (v5.3.0): forms/field.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import { getUID, isElement } from '../util/index'
|
||||
import EventHandler from '../dom/event-handler'
|
||||
import BaseComponent from '../base-component'
|
||||
import SelectorEngine from '../dom/selector-engine'
|
||||
import TemplateFactory from '../util/template-factory'
|
||||
|
||||
const NAME = 'formField'
|
||||
const DATA_KEY = 'bs.field'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const EVENT_INPUT = `input${EVENT_KEY}`
|
||||
const CLASS_FIELD_ERROR = 'is-invalid'
|
||||
const CLASS_FIELD_SUCCESS = 'is-valid'
|
||||
|
||||
const ARIA_DESCRIBED_BY = 'aria-describedby'
|
||||
const Default = {
|
||||
invalid: '', // invalid message to append
|
||||
valid: '', // valid message to append
|
||||
type: 'feedback' // or tooltip
|
||||
}
|
||||
|
||||
const DefaultType = {
|
||||
invalid: 'string',
|
||||
valid: 'string',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const MessageTypes = {
|
||||
ERROR: { prefix: 'invalid', class: CLASS_FIELD_ERROR },
|
||||
INFO: { prefix: 'info', class: '' },
|
||||
SUCCESS: { prefix: 'valid', class: CLASS_FIELD_SUCCESS }
|
||||
}
|
||||
|
||||
class FormField extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
super(element, config)
|
||||
if (!isElement(this._element)) {
|
||||
throw new TypeError(`field "${this._config.name}" not found`)
|
||||
}
|
||||
|
||||
this._tipId = getUID(`${this._config.name}-formTip-`)
|
||||
this._initialDescribedBy = this._element.getAttribute(ARIA_DESCRIBED_BY) || ''
|
||||
|
||||
EventHandler.on(this._element, EVENT_INPUT, () => {
|
||||
this.clearAppended()
|
||||
})
|
||||
}
|
||||
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DefaultType() {
|
||||
return DefaultType
|
||||
}
|
||||
|
||||
static get MessageTypes() {
|
||||
return MessageTypes
|
||||
}
|
||||
|
||||
clearAppended() {
|
||||
const appendedFeedback = SelectorEngine.findOne(`#${this._tipId}`, this._element.parentNode)
|
||||
if (!appendedFeedback) {
|
||||
return
|
||||
}
|
||||
|
||||
appendedFeedback.remove()
|
||||
|
||||
this._element.classList.remove(CLASS_FIELD_ERROR, CLASS_FIELD_SUCCESS)
|
||||
|
||||
if (this._initialDescribedBy) {
|
||||
this._element.setAttribute(ARIA_DESCRIBED_BY, this._initialDescribedBy)
|
||||
return
|
||||
}
|
||||
|
||||
this._element.removeAttribute(ARIA_DESCRIBED_BY)
|
||||
}
|
||||
|
||||
appendError(message = this._config.invalid) {
|
||||
return this.appendFeedback(message, this.constructor.MessageTypes.ERROR)
|
||||
}
|
||||
|
||||
appendSuccess(message = this._config.valid) {
|
||||
return this.appendFeedback(message, this.constructor.MessageTypes.SUCCESS)
|
||||
}
|
||||
|
||||
appendFeedback(feedback, classes = this.constructor.MessageTypes.INFO) {
|
||||
if (!feedback) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.clearAppended()
|
||||
|
||||
const config = {
|
||||
extraClass: `${classes.prefix}-${this._config.type} ${classes.class}`,
|
||||
content: { div: feedback }
|
||||
}
|
||||
feedback = new TemplateFactory(config)
|
||||
|
||||
const feedbackElement = feedback.toHtml()
|
||||
feedbackElement.id = this._tipId
|
||||
|
||||
this._element.parentNode.append(feedbackElement)
|
||||
|
||||
const describedBy = `${this._initialDescribedBy} ${feedbackElement.id}`.trim()
|
||||
this._element.setAttribute(ARIA_DESCRIBED_BY, describedBy)
|
||||
return true
|
||||
}
|
||||
|
||||
name() {
|
||||
return this._element.name || this._element.id
|
||||
}
|
||||
}
|
||||
|
||||
export default FormField
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap (v5.3.0): util/form-validation.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
import BaseComponent from '../base-component'
|
||||
import EventHandler from '../dom/event-handler'
|
||||
import FormField from './form-field'
|
||||
import SelectorEngine from '../dom/selector-engine'
|
||||
import { execute } from '../util/index'
|
||||
|
||||
const NAME = 'formValidation'
|
||||
const DATA_KEY = 'bs.formValidation'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
|
||||
const EVENT_SUBMIT = `submit${EVENT_KEY}`
|
||||
const EVENT_RESET = `reset${EVENT_KEY}`
|
||||
|
||||
const CLASS_VALIDATED = 'was-validated'
|
||||
const SELECTOR_DATA_TOGGLE = 'form[data-bs-toggle="form"]'
|
||||
|
||||
const Default = {
|
||||
type: 'feedback', // or 'tooltip'
|
||||
validateCallback: null
|
||||
}
|
||||
|
||||
const DefaultType = {
|
||||
type: 'string',
|
||||
validateCallback: '(function|null)'
|
||||
}
|
||||
|
||||
class Form extends BaseComponent {
|
||||
constructor(element, config) {
|
||||
if (element.tagName !== 'FORM') {
|
||||
throw new TypeError(`Need to be initialized in form elements. "${element.tagName}" given`)
|
||||
}
|
||||
|
||||
super(element, config)
|
||||
|
||||
this._formFields = null // form field instances
|
||||
}
|
||||
|
||||
static get NAME() {
|
||||
return NAME
|
||||
}
|
||||
|
||||
static get Default() {
|
||||
return Default
|
||||
}
|
||||
|
||||
static get DefaultType() {
|
||||
return DefaultType
|
||||
}
|
||||
|
||||
getFields() {
|
||||
if (!this._formFields) {
|
||||
this._formFields = this._initializeFields()
|
||||
}
|
||||
|
||||
return this._formFields
|
||||
}
|
||||
|
||||
getField(name) {
|
||||
return this.getFields().get(name)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._element.classList.remove(CLASS_VALIDATED)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for (const [name, field] of this.getFields()) {
|
||||
field.clearAppended()
|
||||
}
|
||||
}
|
||||
|
||||
validate() {
|
||||
this.clear()
|
||||
const fetchedErrors = this._fetchErrors()
|
||||
if (this._element.checkValidity() && !Object.keys(fetchedErrors).length) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (const [name, field] of this.getFields()) {
|
||||
this._appendErrorToField(field, fetchedErrors[name] || null)
|
||||
}
|
||||
|
||||
this._element.classList.add(CLASS_VALIDATED)
|
||||
return false
|
||||
}
|
||||
|
||||
_appendErrorToField(field, givenMessage) {
|
||||
const element = field.getElement()
|
||||
|
||||
if (givenMessage) { // if field is invalid check and return for default message
|
||||
field.appendError(givenMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if (element.checkValidity()) { // if field is valid, return first success message
|
||||
field.appendSuccess()
|
||||
return
|
||||
}
|
||||
|
||||
if (field.appendError()) { // if field is invalid check and return for default message
|
||||
return
|
||||
}
|
||||
|
||||
field.appendError(element.validationMessage)
|
||||
}
|
||||
|
||||
_initializeFields() {
|
||||
const fields = new Map()
|
||||
const formElements = Array.from(this._element.elements) // the DOM elements
|
||||
for (const element of formElements) {
|
||||
const field = FormField.getOrCreateInstance(element, {
|
||||
type: this._config.type
|
||||
})
|
||||
fields.set(field.name(), field)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
_fetchErrors() {
|
||||
return execute(this._config.validateCallback, [this], {})
|
||||
}
|
||||
}
|
||||
|
||||
// On submit we want to auto-validate form
|
||||
EventHandler.on(document, EVENT_SUBMIT, SELECTOR_DATA_TOGGLE, event => {
|
||||
const { target } = event
|
||||
const instance = Form.getOrCreateInstance(target)
|
||||
if (!target.checkValidity()) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
if (instance.validate()) {
|
||||
target.submit()
|
||||
}
|
||||
})
|
||||
|
||||
EventHandler.on(document, EVENT_RESET, SELECTOR_DATA_TOGGLE, event => {
|
||||
const { target } = event
|
||||
const instance = Form.getOrCreateInstance(target)
|
||||
|
||||
instance.clear()
|
||||
})
|
||||
|
||||
// On load, add `novalidate` attribute to avoid browser validation
|
||||
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
||||
for (const el of SelectorEngine.find(SELECTOR_DATA_TOGGLE)) {
|
||||
el.setAttribute('novalidate', true)
|
||||
}
|
||||
})
|
||||
export default Form
|
||||
|
||||
@@ -4,8 +4,6 @@ title: مثال إتمام الشراء
|
||||
direction: rtl
|
||||
extra_css:
|
||||
- "../checkout/checkout.css"
|
||||
extra_js:
|
||||
- src: "../checkout/checkout.js"
|
||||
body_class: "bg-light"
|
||||
---
|
||||
|
||||
@@ -67,7 +65,7 @@ body_class: "bg-light"
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-8">
|
||||
<h4 class="mb-3">عنوان الفوترة</h4>
|
||||
<form class="needs-validation" novalidate>
|
||||
<form data-bs-toggle="form">
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6">
|
||||
<label for="firstName" class="form-label">الاسم الأول</label>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Example starter JavaScript for disabling form submissions if there are invalid fields
|
||||
(() => {
|
||||
'use strict'
|
||||
|
||||
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
||||
const forms = document.querySelectorAll('.needs-validation')
|
||||
|
||||
// Loop over them and prevent submission
|
||||
Array.from(forms).forEach(form => {
|
||||
form.addEventListener('submit', event => {
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
form.classList.add('was-validated')
|
||||
}, false)
|
||||
})
|
||||
})()
|
||||
@@ -3,8 +3,6 @@ layout: examples
|
||||
title: Checkout example
|
||||
extra_css:
|
||||
- "checkout.css"
|
||||
extra_js:
|
||||
- src: "checkout.js"
|
||||
body_class: "bg-light"
|
||||
---
|
||||
|
||||
@@ -66,7 +64,7 @@ body_class: "bg-light"
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-8">
|
||||
<h4 class="mb-3">Billing address</h4>
|
||||
<form class="needs-validation" novalidate>
|
||||
<form data-bs-toggle="form">
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6">
|
||||
<label for="firstName" class="form-label">First name</label>
|
||||
|
||||
@@ -4,15 +4,8 @@ title: Validation
|
||||
description: Provide valuable, actionable feedback to your users with HTML5 form validation, via browser default behaviors or custom styles and JavaScript.
|
||||
group: forms
|
||||
toc: true
|
||||
extra_js:
|
||||
- src: "/docs/5.2/assets/js/validate-forms.js"
|
||||
async: true
|
||||
---
|
||||
|
||||
{{< callout warning >}}
|
||||
We are aware that currently the client-side custom validation styles and tooltips are not accessible, since they are not exposed to assistive technologies. While we work on a solution, we'd recommend either using the server-side option or the default browser validation method.
|
||||
{{< /callout >}}
|
||||
|
||||
## How it works
|
||||
|
||||
Here's how form validation works with Bootstrap:
|
||||
@@ -30,80 +23,59 @@ With that in mind, consider the following demos for our custom form validation s
|
||||
|
||||
## Custom styles
|
||||
|
||||
For custom Bootstrap form validation messages, you'll need to add the `novalidate` boolean attribute to your `<form>`. This disables the browser default feedback tooltips, but still provides access to the form validation APIs in JavaScript. Try to submit the form below; our JavaScript will intercept the submit button and relay feedback to you. When attempting to submit, you'll see the `:invalid` and `:valid` styles applied to your form controls.
|
||||
For custom Bootstrap form validation messages, you'll need to add the data-bs-toggle="form" `<form>`. This disables the browser default feedback tooltips, but still provides access to the form validation APIs in JavaScript. Try to submit the form below; our JavaScript will intercept the submit button and relay feedback to you. When attempting to submit, you'll see the `:invalid` and `:valid` styles applied to your form controls.
|
||||
|
||||
Custom feedback styles apply custom colors, borders, focus styles, and background icons to better communicate feedback. Background icons for `<select>`s are only available with `.form-select`, and not `.form-control`.
|
||||
|
||||
{{< example >}}
|
||||
<form class="row g-3 needs-validation" novalidate>
|
||||
<form class="row g-3" data-bs-toggle="form">
|
||||
<div class="col-md-4">
|
||||
<label for="validationCustom01" class="form-label">First name</label>
|
||||
<input type="text" class="form-control" id="validationCustom01" value="Mark" required>
|
||||
<div class="valid-feedback">
|
||||
Looks good!
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationCustom01" value="Mark" required data-bs-valid="Looks good!" data-bs-invalid="Please, provide a valid Name!">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="validationCustom02" class="form-label">Last name</label>
|
||||
<input type="text" class="form-control" id="validationCustom02" value="Otto" required>
|
||||
<div class="valid-feedback">
|
||||
Looks good!
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationCustom02" value="Otto" required data-bs-valid="Looks good!">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="validationCustomUsername" class="form-label">Username</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text" id="inputGroupPrepend">@</span>
|
||||
<input type="text" class="form-control" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required>
|
||||
<div class="invalid-feedback">
|
||||
Please choose a username.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required data-bs-invalid="Please choose a username.">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="validationCustom03" class="form-label">City</label>
|
||||
<input type="text" class="form-control" id="validationCustom03" required>
|
||||
<div class="invalid-feedback">
|
||||
Please provide a valid city.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationCustom03" required data-bs-invalid="Please provide a valid city.">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="validationCustom04" class="form-label">State</label>
|
||||
<select class="form-select" id="validationCustom04" required>
|
||||
<select class="form-select" id="validationCustom04" required data-bs-invalid="Please select a valid state.">
|
||||
<option selected disabled value="">Choose...</option>
|
||||
<option>...</option>
|
||||
</select>
|
||||
<div class="invalid-feedback">
|
||||
Please select a valid state.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="validationCustom05" class="form-label">Zip</label>
|
||||
<input type="text" class="form-control" id="validationCustom05" required>
|
||||
<div class="invalid-feedback">
|
||||
Please provide a valid zip.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationCustom05" required data-bs-invalid="Please provide a valid zip.">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
|
||||
<input class="form-check-input" type="checkbox" value="" id="invalidCheck" required data-bs-invalid="You must agree before submitting.">
|
||||
<label class="form-check-label" for="invalidCheck">
|
||||
Agree to terms and conditions
|
||||
</label>
|
||||
<div class="invalid-feedback">
|
||||
You must agree before submitting.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button class="btn btn-primary" type="submit">Submit form</button>
|
||||
<button class="btn btn-danger" type="reset">Reset form</button>
|
||||
</div>
|
||||
</form>
|
||||
{{< /example >}}
|
||||
|
||||
{{< example lang="js" show_preview="false" >}}
|
||||
{{< js.inline >}}
|
||||
{{- readFile (path.Join "site/static/docs" .Site.Params.docs_version "assets/js/validate-forms.js") -}}
|
||||
{{< /js.inline >}}
|
||||
{{< /example >}}
|
||||
|
||||
@@ -163,7 +135,7 @@ While these feedback styles cannot be styled with CSS, you can still customize t
|
||||
|
||||
We recommend using client-side validation, but in case you require server-side validation, you can indicate invalid and valid form fields with `.is-invalid` and `.is-valid`. Note that `.invalid-feedback` is also supported with these classes.
|
||||
|
||||
For invalid fields, ensure that the invalid feedback/error message is associated with the relevant form field using `aria-describedby` (noting that this attribute allows more than one `id` to be referenced, in case the field already points to additional form text).
|
||||
Ensure that the feedback/error message is associated with the relevant form field using `aria-describedby` (noting that this attribute allows more than one `id` to be referenced, in case the field already points to additional form text).
|
||||
|
||||
To fix [issues with border radius](https://github.com/twbs/bootstrap/issues/25110), input groups require an additional `.has-validation` class.
|
||||
|
||||
@@ -171,15 +143,15 @@ To fix [issues with border radius](https://github.com/twbs/bootstrap/issues/2511
|
||||
<form class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label for="validationServer01" class="form-label">First name</label>
|
||||
<input type="text" class="form-control is-valid" id="validationServer01" value="Mark" required>
|
||||
<div class="valid-feedback">
|
||||
<input type="text" class="form-control is-valid" id="validationServer01" value="Mark" aria-describedby="validationServerNameFeedback" required>
|
||||
<div id="validationServerNameFeedback" class="valid-feedback">
|
||||
Looks good!
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="validationServer02" class="form-label">Last name</label>
|
||||
<input type="text" class="form-control is-valid" id="validationServer02" value="Otto" required>
|
||||
<div class="valid-feedback">
|
||||
<input type="text" class="form-control is-valid" id="validationServer02" aria-describedby="validationServerLastNameFeedback" value="Otto" required>
|
||||
<div id="validationServerLastNameFeedback" class="valid-feedback">
|
||||
Looks good!
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,41 +218,41 @@ Validation styles are available for the following form controls and components:
|
||||
<form class="was-validated">
|
||||
<div class="mb-3">
|
||||
<label for="validationTextarea" class="form-label">Textarea</label>
|
||||
<textarea class="form-control" id="validationTextarea" placeholder="Required example textarea" required></textarea>
|
||||
<div class="invalid-feedback">
|
||||
<textarea class="form-control" id="validationTextarea" placeholder="Required example textarea" aria-describedby="validationSupportedElementsTextArea" required></textarea>
|
||||
<div id="validationSupportedElementsTextArea" class="invalid-feedback">
|
||||
Please enter a message in the textarea.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" class="form-check-input" id="validationFormCheck1" required>
|
||||
<input type="checkbox" class="form-check-input" id="validationFormCheck1" aria-describedby="validationSupportedElementsCheckBox" required>
|
||||
<label class="form-check-label" for="validationFormCheck1">Check this checkbox</label>
|
||||
<div class="invalid-feedback">Example invalid feedback text</div>
|
||||
<div id="validationSupportedElementsCheckBox" class="invalid-feedback">Example invalid feedback text</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input type="radio" class="form-check-input" id="validationFormCheck2" name="radio-stacked" required>
|
||||
<input type="radio" class="form-check-input" id="validationFormCheck2" name="radio-stacked" aria-describedby="validationSupportedElementsRadio" required>
|
||||
<label class="form-check-label" for="validationFormCheck2">Toggle this radio</label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="radio" class="form-check-input" id="validationFormCheck3" name="radio-stacked" required>
|
||||
<input type="radio" class="form-check-input" id="validationFormCheck3" name="radio-stacked" aria-describedby="validationSupportedElementsRadio" required>
|
||||
<label class="form-check-label" for="validationFormCheck3">Or toggle this other radio</label>
|
||||
<div class="invalid-feedback">More example invalid feedback text</div>
|
||||
<div id="validationSupportedElementsRadio" class="invalid-feedback">More example invalid feedback text</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<select class="form-select" required aria-label="select example">
|
||||
<select class="form-select" required aria-label="select example" aria-describedby="validationSupportedElementsSelect">
|
||||
<option value="">Open this select menu</option>
|
||||
<option value="1">One</option>
|
||||
<option value="2">Two</option>
|
||||
<option value="3">Three</option>
|
||||
</select>
|
||||
<div class="invalid-feedback">Example invalid select feedback</div>
|
||||
<div id="validationSupportedElementsSelect" class="invalid-feedback">Example invalid select feedback</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control" aria-label="file example" required>
|
||||
<div class="invalid-feedback">Example invalid form file feedback</div>
|
||||
<input type="file" class="form-control" aria-label="file example" required aria-describedby="validationSupportedElementsFile">
|
||||
<div id="validationSupportedElementsFile" class="invalid-feedback">Example invalid form file feedback</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
@@ -294,57 +266,40 @@ Validation styles are available for the following form controls and components:
|
||||
If your form layout allows it, you can swap the `.{valid|invalid}-feedback` classes for `.{valid|invalid}-tooltip` classes to display validation feedback in a styled tooltip. Be sure to have a parent with `position: relative` on it for tooltip positioning. In the example below, our column classes have this already, but your project may require an alternative setup.
|
||||
|
||||
{{< example >}}
|
||||
<form class="row g-3 needs-validation" novalidate>
|
||||
<form class="row g-3" data-bs-toggle="form" data-bs-type="tooltip" >
|
||||
<div class="col-md-4 position-relative">
|
||||
<label for="validationTooltip01" class="form-label">First name</label>
|
||||
<input type="text" class="form-control" id="validationTooltip01" value="Mark" required>
|
||||
<div class="valid-tooltip">
|
||||
Looks good!
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationTooltip01" value="Mark" required data-bs-valid="Looks good!">
|
||||
</div>
|
||||
<div class="col-md-4 position-relative">
|
||||
<label for="validationTooltip02" class="form-label">Last name</label>
|
||||
<input type="text" class="form-control" id="validationTooltip02" value="Otto" required>
|
||||
<div class="valid-tooltip">
|
||||
Looks good!
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationTooltip02" value="Otto" required data-bs-valid="Looks good!">
|
||||
</div>
|
||||
<div class="col-md-4 position-relative">
|
||||
<label for="validationTooltipUsername" class="form-label">Username</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text" id="validationTooltipUsernamePrepend">@</span>
|
||||
<input type="text" class="form-control" id="validationTooltipUsername" aria-describedby="validationTooltipUsernamePrepend" required>
|
||||
<div class="invalid-tooltip">
|
||||
Please choose a unique and valid username.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationTooltipUsername" aria-describedby="validationTooltipUsernamePrepend" required data-bs-invalid="Please choose a username.">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 position-relative">
|
||||
<label for="validationTooltip03" class="form-label">City</label>
|
||||
<input type="text" class="form-control" id="validationTooltip03" required>
|
||||
<div class="invalid-tooltip">
|
||||
Please provide a valid city.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationTooltip03" required data-bs-invalid="Please provide a valid city.">
|
||||
</div>
|
||||
<div class="col-md-3 position-relative">
|
||||
<label for="validationTooltip04" class="form-label">State</label>
|
||||
<select class="form-select" id="validationTooltip04" required>
|
||||
<select class="form-select" id="validationTooltip04" required data-bs-invalid="Please select a valid state.">
|
||||
<option selected disabled value="">Choose...</option>
|
||||
<option>...</option>
|
||||
</select>
|
||||
<div class="invalid-tooltip">
|
||||
Please select a valid state.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 position-relative">
|
||||
<label for="validationTooltip05" class="form-label">Zip</label>
|
||||
<input type="text" class="form-control" id="validationTooltip05" required>
|
||||
<div class="invalid-tooltip">
|
||||
Please provide a valid zip.
|
||||
</div>
|
||||
<input type="text" class="form-control" id="validationTooltip05" required data-bs-invalid="Please provide a valid zip.">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button class="btn btn-primary" type="submit">Submit form</button>
|
||||
<button class="btn btn-danger" type="reset">Reset form</button>
|
||||
</div>
|
||||
</form>
|
||||
{{< /example >}}
|
||||
@@ -378,3 +333,73 @@ Used to iterate over `$form-validation-states` map values to generate our valida
|
||||
### Customizing
|
||||
|
||||
Validation states can be customized via Sass with the `$form-validation-states` map. Located in our `_variables.scss` file, this Sass map is how we generate the default `valid`/`invalid` validation states. Included is a nested map for customizing each state's color, icon, tooltip color, and focus shadow. While no other states are supported by browsers, those using custom styles can easily add more complex form feedback.
|
||||
|
||||
|
||||
## Usage
|
||||
### Via data attributes
|
||||
|
||||
To easily add form validation behavior to you form, add `data-bs-toggle="form"` attribute to the `<form>` element.
|
||||
|
||||
### Via JavaScript
|
||||
|
||||
Enable manually with:
|
||||
|
||||
```js
|
||||
const formElementList = document.querySelectorAll('form')
|
||||
const formList = [...formElementList].map(formEl => new bootstrap.Form(formEl))
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
#### Form
|
||||
{{< bs-table "table" >}}
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `type` | string | `feedback` | You may pick the kind of feedback. Acceptable values `tooltip` or `feedback` |
|
||||
| `validateCallback` | function, null | `null` | A callback to execute while trying to check for errors. Can be use for ajax submissions/validations. |
|
||||
{{< /bs-table >}}
|
||||
|
||||
|
||||
#### Field
|
||||
{{< bs-table "table" >}}
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `invalid` | string | `''` | invalid message to append |
|
||||
| `valid` | string | `''` | valid message to append |
|
||||
{{< /bs-table >}}
|
||||
|
||||
### Methods
|
||||
|
||||
|
||||
You can create a form instance using the constructor, for example:
|
||||
|
||||
```js
|
||||
const bsForm = new bootstrap.Form('#myForm', { type: 'tooltip' })
|
||||
```
|
||||
|
||||
#### Form
|
||||
{{< bs-table "table" >}}
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `getInstance` | *Static* method which allows you to get the form instance associated with a DOM element. |
|
||||
| `getOrCreateInstance` | *Static* method which allows you to get the form instance associated with a DOM element, or create a new one in case it wasn't initialized. |
|
||||
| `getElement` | Returns the DOM element of the instance. |
|
||||
| `getFields` | Returns all form-fields instances of the form. Array\<FormField\>. |
|
||||
| `getField('name')` | Searches and return the requested FormField instance or undefined. |
|
||||
| `clear` | Clears all the form validation results. |
|
||||
| `validate` | Activates validation process. |
|
||||
{{< /bs-table >}}
|
||||
|
||||
#### Field
|
||||
{{< bs-table "table" >}}
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `getInstance` | *Static* method which allows you to get the form Field instance associated with a DOM element |
|
||||
| `getOrCreateInstance` | *Static* method which allows you to get the form Field instance associated with a DOM element, or create a new one in case it wasn't initialized |
|
||||
| `getElement` | Returns the DOM element of the instance. |
|
||||
| `clearAppended` | Clears any appended messages from field. |
|
||||
| `appendError(message)` | Appends the given message as an error feedback. In case we do not provide a message, it fallbacks to the configuration given `invalid` message. |
|
||||
| `appendSuccess(message)` | Appends the given message as a success feedback. In case we do not provide a message, it fallbacks to the configuration given `valid` message. |
|
||||
| `appendFeedback(message)` | Appends the given message as a simple info feedback. |
|
||||
| `name` | returns the name (fallback to id) of the field as unique identifier between form elements. |
|
||||
{{< /bs-table >}}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Example starter JavaScript for disabling form submissions if there are invalid fields
|
||||
(() => {
|
||||
'use strict'
|
||||
|
||||
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
||||
const forms = document.querySelectorAll('.needs-validation')
|
||||
|
||||
// Loop over them and prevent submission
|
||||
Array.from(forms).forEach(form => {
|
||||
form.addEventListener('submit', event => {
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
form.classList.add('was-validated')
|
||||
}, false)
|
||||
})
|
||||
})()
|
||||
Reference in New Issue
Block a user