diff --git a/docs/api/input-otp.mdx b/docs/api/input-otp.mdx index 537f49b197..beefdfe124 100644 --- a/docs/api/input-otp.mdx +++ b/docs/api/input-otp.mdx @@ -103,6 +103,16 @@ import States from '@site/static/usage/v9/input-otp/states/index.mdx'; +## Helper & Error Text {/* #helper--error-text */} + +Helper and error text can be displayed under the input boxes with the `helperText` and `errorText` properties. The error text isn't displayed unless the `ion-invalid` and `ion-touched` classes are added to the `ion-input-otp`, so errors aren't shown before the user has a chance to enter a code. + +In Angular, this is done automatically through form validation. In JavaScript, React and Vue, the classes need to be added manually based on your own validation. + +import HelperError from '@site/static/usage/v9/input-otp/helper-error/index.mdx'; + + + ## Pattern {/* #pattern */} The `pattern` property enables custom validation using regular expressions. It accepts a [string regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Cheatsheet) or [unicode regular expression](https://www.regular-expressions.info/unicode.html) to validate allowed characters. The `pattern` must match the entire value, not just a subset. Default patterns: @@ -151,6 +161,20 @@ import CSSProps from '@site/static/usage/v9/input-otp/theming/css-properties/ind ## Accessibility {/* #accessibility */} +### Labels {/* #labels */} + +Each input box is announced with its position, such as "Input 1 of 4". When `aria-label` is set on `ion-input-otp`, it's added to the start of each name, such as "PIN, 1 of 4". An element referenced with `aria-labelledby` works the same way. + +The `inputLabelFormatter` property can be used to translate the names. It receives the 0-based `index` of the box and the total `length`, and its return value is used as the full name of the box. + +```javascript +inputOtp.inputLabelFormatter = (index, length) => `Ziffer ${index + 1} von ${length}`; +``` + +### Focus Indicator {/* #focus-indicator */} + +The focused input box is indicated by its border color. Set `--highlight-color-focused` to change this color, or `--highlight-color-valid` and `--highlight-color-invalid` to change it when the input has a validation state. If you change these colors, adjust `--border-color`, which styles the unfocused boxes, so the focused box still stands out. + ### Keyboard Interactions {/* #keyboard-interactions */} The keyboard navigation for Input OTP follows the [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/)'s recommendations for composite widgets. It is treated as a composite widget because it contains multiple focusable elements (input boxes) that function as a single control. diff --git a/static/usage/v9/input-otp/helper-error/angular/example_component_html.md b/static/usage/v9/input-otp/helper-error/angular/example_component_html.md new file mode 100644 index 0000000000..ca1b6972b9 --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/angular/example_component_html.md @@ -0,0 +1,11 @@ +```html + +``` diff --git a/static/usage/v9/input-otp/helper-error/angular/example_component_ts.md b/static/usage/v9/input-otp/helper-error/angular/example_component_ts.md new file mode 100644 index 0000000000..2a9ba701fc --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/angular/example_component_ts.md @@ -0,0 +1,13 @@ +```ts +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { IonInputOtp } from '@ionic/angular'; + +@Component({ + selector: 'app-example', + templateUrl: 'example.component.html', + styleUrls: ['example.component.css'], + imports: [IonInputOtp, FormsModule], +}) +export class ExampleComponent {} +``` diff --git a/static/usage/v9/input-otp/helper-error/demo.html b/static/usage/v9/input-otp/helper-error/demo.html new file mode 100644 index 0000000000..75f259f7c5 --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/demo.html @@ -0,0 +1,45 @@ + + + + + + Input OTP + + + + + + + + + +
+ +
+
+
+ + + + diff --git a/static/usage/v9/input-otp/helper-error/index.mdx b/static/usage/v9/input-otp/helper-error/index.mdx new file mode 100644 index 0000000000..81dc973210 --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/index.mdx @@ -0,0 +1,25 @@ +import Playground from '@site/src/components/global/Playground'; + +import javascript from './javascript.md'; +import react from './react.md'; +import vue from './vue.md'; + +import angular_example_component_html from './angular/example_component_html.md'; +import angular_example_component_ts from './angular/example_component_ts.md'; + + diff --git a/static/usage/v9/input-otp/helper-error/javascript.md b/static/usage/v9/input-otp/helper-error/javascript.md new file mode 100644 index 0000000000..2e08ee4477 --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/javascript.md @@ -0,0 +1,23 @@ +```html + + + +``` diff --git a/static/usage/v9/input-otp/helper-error/react.md b/static/usage/v9/input-otp/helper-error/react.md new file mode 100644 index 0000000000..c793e1a868 --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/react.md @@ -0,0 +1,28 @@ +```tsx +import React, { useState } from 'react'; +import { IonInputOtp } from '@ionic/react'; + +function Example() { + const [isTouched, setIsTouched] = useState(false); + const [isValid, setIsValid] = useState(); + + const validate = (value: string) => { + setIsValid(value.length === 4); + }; + + const markTouched = () => { + setIsTouched(true); + }; + + return ( + validate(event.detail.value ?? '')} + onIonBlur={() => markTouched()} + > + ); +} +export default Example; +``` diff --git a/static/usage/v9/input-otp/helper-error/vue.md b/static/usage/v9/input-otp/helper-error/vue.md new file mode 100644 index 0000000000..ec21d8257e --- /dev/null +++ b/static/usage/v9/input-otp/helper-error/vue.md @@ -0,0 +1,33 @@ +```html + + + +```