Skip to content

feat(input-otp): add new input-otp component #30386

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 82 commits into
base: feature-8.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
12b7500
feat(input-otp): add input-otp component
brandyscarney Apr 30, 2025
231b2b0
test(input-otp): add tests for different props
brandyscarney Apr 30, 2025
eb1a8d5
fix(input-otp): fix styles for sizes, spaces and separators
brandyscarney Apr 30, 2025
ce38d95
style: lint
brandyscarney Apr 30, 2025
ee6f29d
fix(input-otp): design fixes and invalid state
brandyscarney May 1, 2025
d5c7c22
Merge branch 'feature-8.6' into FW-6410
brandyscarney May 1, 2025
2d0441c
fix(input-otp): update implementation to match input's more closely
brandyscarney May 1, 2025
5214878
feat(input-otp): add readonly support
brandyscarney May 1, 2025
30eed51
feat(input-otp): support disabled and readonly colors
brandyscarney May 1, 2025
46e69c8
fix(input-otp): resolve a11y error with input labels
brandyscarney May 1, 2025
2e2eebd
refactor(input-otp): clean up and build
brandyscarney May 1, 2025
fcb8e1d
test(input-otp): add tests for basic, color, fill, separators, shape,…
brandyscarney May 2, 2025
3e4fe5a
fix(input-otp): shift input boxes over 1 when clearing a value in the…
brandyscarney May 2, 2025
aeace76
refactor(input-otp): rename allowedKeys to pattern
brandyscarney May 2, 2025
5c7a311
fix(input-otp): paste from first empty box or first box if all are fi…
brandyscarney May 5, 2025
b260644
test(input-otp): paste functionality
brandyscarney May 5, 2025
9aaeef2
fix(input-otp): improve separator collapse
brandyscarney May 5, 2025
6175dfb
fix(input-otp): move focus to last input when all are filled
brandyscarney May 5, 2025
bb7065b
fix(input-otp): always start value at first empty input when typing
brandyscarney May 5, 2025
ecf1c11
fix(input-otp): allow entering keys in the middle of the input group
brandyscarney May 6, 2025
46a3fb7
refactor(input-otp): return when pasted text is empty
brandyscarney May 6, 2025
97649a0
fix(input-otp): respect case when checking pattern
brandyscarney May 6, 2025
eb6ae3f
test(input-otp): add another focus test
brandyscarney May 6, 2025
9b39100
fix(input-otp): update emitted events to match the input component
brandyscarney May 7, 2025
1666307
fix(input-otp): handle arrow navigation in RTL and add RTL tests
brandyscarney May 7, 2025
f9a33ae
test(input): revert logs
brandyscarney May 7, 2025
a9a31ab
fix(input-otp): print a warning when separators exceed length
brandyscarney May 7, 2025
618575d
fix(input-otp): warn for incorrectly formatted separator strings
brandyscarney May 7, 2025
344c72a
feat(input-otp): expose reset and setFocus methods
brandyscarney May 8, 2025
c4743fe
fix(input-otp): move separator next to native wrapper to properly col…
brandyscarney May 8, 2025
f0fba1d
refactor(input-otp): ignore Fragment error in eslint
brandyscarney May 8, 2025
a7d14f2
fix(input-otp): don't allow focus in boxes without values except last
brandyscarney May 8, 2025
6190d0c
fix(input-otp): update colors and valid/invalid states design
brandyscarney May 8, 2025
6b65ceb
fix(input-otp): do not shift values right if the input value is selected
brandyscarney May 8, 2025
9b6ee1e
style: lint
brandyscarney May 8, 2025
cb989bf
fix(input-otp): update ios and md designs
brandyscarney May 12, 2025
f4dca87
test(input-otp): fix duplicate names and old test structure
brandyscarney May 12, 2025
535b737
chore: build
brandyscarney May 12, 2025
64cf4e7
fix(input-otp): update disabled text color
brandyscarney May 12, 2025
3ae2fff
test(input-otp): set explicit height to capture full screenshot
brandyscarney May 12, 2025
2c610e8
chore(): add updated snapshots
brandyscarney May 12, 2025
a968721
style: remove escapes
brandyscarney May 12, 2025
b47fa98
feat(input-otp): support autocapitalize
brandyscarney May 12, 2025
ccedd96
chore(): add updated snapshots
Ionitron May 12, 2025
a9008cd
Revert "chore(): add updated snapshots"
brandyscarney May 12, 2025
a46322b
revert
brandyscarney May 12, 2025
18e0f70
test(input-otp): simplify basic test with helper function to verify v…
brandyscarney May 12, 2025
cbf963d
test(input-otp): add helper functions and constants, warn for duplica…
brandyscarney May 12, 2025
dd7476b
fix(input-otp): extract pattern to a function
brandyscarney May 12, 2025
e02aa1a
Update core/src/components/input-otp/input-otp.tsx
brandyscarney May 13, 2025
e8be93a
fix(angular): add input-otp to Angular's value accessors
brandyscarney May 19, 2025
c6ae0d4
test(angular): add tests for input-otp in lazy tests
brandyscarney May 19, 2025
d53b808
test(angular): add tests for input-otp in standalone tests
brandyscarney May 19, 2025
26349c5
refactor(input-otp): naming update
brandyscarney May 20, 2025
eb7f838
refactor(input-otp): remove redundant code
brandyscarney May 20, 2025
2a9c274
fix(input-otp): allow characters outside of latin when type is text
brandyscarney May 20, 2025
72755ce
style: lint
brandyscarney May 20, 2025
ec35637
refactor(input-otp): change for loop to findIndex
brandyscarney May 20, 2025
b0fea61
style: lint
brandyscarney May 20, 2025
1c9c939
fix(input-otp): allow any kind of numeric character in any script for…
brandyscarney May 20, 2025
d1dc603
docs(input-otp): add code blocks in docs
brandyscarney May 21, 2025
ff4bb55
docs(input-otp): document as single slash
brandyscarney May 21, 2025
acbba7c
test(input-otp): use script pattern in e2e test
brandyscarney May 22, 2025
c5e97c3
fix(input-otp): inherit aria attributes and hide empty input boxes fr…
brandyscarney May 22, 2025
9d905b2
fix(input-otp): hide description when there is no content
brandyscarney May 22, 2025
4015ee4
fix(input-otp): properly handle value updates and add tests
brandyscarney May 23, 2025
82d086f
test(input-otp): clarify the JS behavior of RTL languages in the e2e …
brandyscarney May 23, 2025
8c29200
fix(input-otp): correct paste behavior to always start at first box
brandyscarney May 23, 2025
24accec
test(vue): add tests for input-otp
brandyscarney May 27, 2025
a6cfbb4
chore(scripts): improve test app build scripts to be faster and more …
brandyscarney May 27, 2025
72ad44a
fix(vue): add v-model binding for input-otp
brandyscarney May 27, 2025
0461608
chore(scripts): update build scripts for test app to remove deleted f…
brandyscarney May 27, 2025
1ffbc0d
test(vue): use proper v-model instead of debug code
brandyscarney May 27, 2025
6b17afc
test(react): add inputs test to test input-otp and other inputs
brandyscarney May 27, 2025
e47f1e7
Merge branch 'feature-8.6' into FW-6410
brandyscarney May 27, 2025
2698faf
chore(scripts): revert build test apps back to cp
brandyscarney May 27, 2025
0094604
fix(angular): exclude ion-input-otp from standalone proxy generation
brandyscarney May 27, 2025
0c457b7
docs(component-guide): add information on new input components
brandyscarney May 27, 2025
3ee6fe8
docs(component-guide): add info on updating angular value accessors
brandyscarney May 28, 2025
15c3ac8
style: order
brandyscarney May 28, 2025
30067b0
docs(component-guide): update output target config steps
brandyscarney May 28, 2025
2de1519
refactor(input-otp): reorganize functions to group by functionality
brandyscarney May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/.eslintrc.js
Copy link
Member Author

@brandyscarney brandyscarney May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was required in order to use <> in input-otp.tsx

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module.exports = {
"@typescript-eslint/no-unused-vars": [
"warn",
{
"varsIgnorePattern": "^h$"
"varsIgnorePattern": "^(h|Fragment)$"
}
],
"no-useless-catch": "off",
Expand Down
68 changes: 68 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,74 @@ ion-input,css-prop,--placeholder-font-weight,md
ion-input,css-prop,--placeholder-opacity,ios
ion-input,css-prop,--placeholder-opacity,md

ion-input-otp,scoped
ion-input-otp,prop,autocapitalize,string,'off',false,false
ion-input-otp,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-input-otp,prop,disabled,boolean,false,false,true
ion-input-otp,prop,fill,"outline" | "solid" | undefined,'outline',false,false
ion-input-otp,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url" | undefined,undefined,false,false
ion-input-otp,prop,length,number,4,false,false
ion-input-otp,prop,pattern,string | undefined,undefined,false,false
ion-input-otp,prop,readonly,boolean,false,false,true
ion-input-otp,prop,separators,number[] | string | undefined,undefined,false,false
ion-input-otp,prop,shape,"rectangular" | "round" | "soft",'round',false,false
ion-input-otp,prop,size,"large" | "medium" | "small",'medium',false,false
ion-input-otp,prop,type,"number" | "text",'number',false,false
ion-input-otp,prop,value,null | number | string | undefined,'',false,false
ion-input-otp,method,reset,reset() => Promise<void>
ion-input-otp,method,setFocus,setFocus(index?: number) => Promise<void>
ion-input-otp,event,ionBlur,FocusEvent,true
ion-input-otp,event,ionChange,InputOtpChangeEventDetail,true
ion-input-otp,event,ionComplete,InputOtpCompleteEventDetail,true
ion-input-otp,event,ionFocus,FocusEvent,true
ion-input-otp,event,ionInput,InputOtpInputEventDetail,true
ion-input-otp,css-prop,--background,ios
ion-input-otp,css-prop,--background,md
ion-input-otp,css-prop,--border-color,ios
ion-input-otp,css-prop,--border-color,md
ion-input-otp,css-prop,--border-radius,ios
ion-input-otp,css-prop,--border-radius,md
ion-input-otp,css-prop,--border-width,ios
ion-input-otp,css-prop,--border-width,md
ion-input-otp,css-prop,--color,ios
ion-input-otp,css-prop,--color,md
ion-input-otp,css-prop,--height,ios
ion-input-otp,css-prop,--height,md
ion-input-otp,css-prop,--highlight-color-focused,ios
ion-input-otp,css-prop,--highlight-color-focused,md
ion-input-otp,css-prop,--highlight-color-invalid,ios
ion-input-otp,css-prop,--highlight-color-invalid,md
ion-input-otp,css-prop,--highlight-color-valid,ios
ion-input-otp,css-prop,--highlight-color-valid,md
ion-input-otp,css-prop,--margin-bottom,ios
ion-input-otp,css-prop,--margin-bottom,md
ion-input-otp,css-prop,--margin-end,ios
ion-input-otp,css-prop,--margin-end,md
ion-input-otp,css-prop,--margin-start,ios
ion-input-otp,css-prop,--margin-start,md
ion-input-otp,css-prop,--margin-top,ios
ion-input-otp,css-prop,--margin-top,md
ion-input-otp,css-prop,--min-width,ios
ion-input-otp,css-prop,--min-width,md
ion-input-otp,css-prop,--padding-bottom,ios
ion-input-otp,css-prop,--padding-bottom,md
ion-input-otp,css-prop,--padding-end,ios
ion-input-otp,css-prop,--padding-end,md
ion-input-otp,css-prop,--padding-start,ios
ion-input-otp,css-prop,--padding-start,md
ion-input-otp,css-prop,--padding-top,ios
ion-input-otp,css-prop,--padding-top,md
ion-input-otp,css-prop,--separator-border-radius,ios
ion-input-otp,css-prop,--separator-border-radius,md
ion-input-otp,css-prop,--separator-color,ios
ion-input-otp,css-prop,--separator-color,md
ion-input-otp,css-prop,--separator-height,ios
ion-input-otp,css-prop,--separator-height,md
ion-input-otp,css-prop,--separator-width,ios
ion-input-otp,css-prop,--separator-width,md
ion-input-otp,css-prop,--width,ios
ion-input-otp,css-prop,--width,md

ion-input-password-toggle,shadow
ion-input-password-toggle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-input-password-toggle,prop,hideIcon,string | undefined,undefined,false,false
Expand Down
167 changes: 167 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ScrollBaseDetail, ScrollDetail } from "./components/content/content-int
import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
import { SpinnerTypes } from "./components/spinner/spinner-configs";
import { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
import { InputOtpChangeEventDetail, InputOtpCompleteEventDetail, InputOtpInputEventDetail } from "./components/input-otp/input-otp-interface";
import { MenuChangeEventDetail, MenuCloseEventDetail, MenuType, Side } from "./components/menu/menu-interface";
import { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
Expand Down Expand Up @@ -55,6 +56,7 @@ export { ScrollBaseDetail, ScrollDetail } from "./components/content/content-int
export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
export { SpinnerTypes } from "./components/spinner/spinner-configs";
export { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
export { InputOtpChangeEventDetail, InputOtpCompleteEventDetail, InputOtpInputEventDetail } from "./components/input-otp/input-otp-interface";
export { MenuChangeEventDetail, MenuCloseEventDetail, MenuType, Side } from "./components/menu/menu-interface";
export { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
Expand Down Expand Up @@ -1319,6 +1321,69 @@ export namespace Components {
*/
"value"?: string | number | null;
}
interface IonInputOtp {
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
"autocapitalize": string;
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* If `true`, the user cannot interact with the input.
*/
"disabled": boolean;
/**
* The fill for the input boxes. If `"solid"` the input boxes will have a background. If `"outline"` the input boxes will be transparent with a border.
*/
"fill"?: 'outline' | 'solid';
/**
* A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. For numbers (type="number"): "numeric" For text (type="text"): "text"
*/
"inputmode"?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
/**
* The number of input boxes to display.
*/
"length": number;
/**
* A regex pattern string for allowed characters. Defaults based on type. For numbers (`type="number"`): `"[\p{N}]"` For text (`type="text"`): `"[\p{L}\p{N}]"`
*/
"pattern"?: string;
/**
* If `true`, the user cannot modify the value.
*/
"readonly": boolean;
/**
* Resets the value and focus state.
*/
"reset": () => Promise<void>;
/**
* Where separators should be shown between input boxes. Can be a comma-separated string or an array of numbers. For example: `"3"` will show a separator after the 3rd input box. `[1,4]` will show a separator after the 1st and 4th input boxes. `"all"` will show a separator between every input box.
*/
"separators"?: 'all' | string | number[];
/**
* Sets focus to an input box.
* @param index - The index of the input box to focus (0-based). If provided and the input box has a value, the input box at that index will be focused. Otherwise, the first empty input box or the last input if all are filled will be focused.
*/
"setFocus": (index?: number) => Promise<void>;
/**
* The shape of the input boxes. If "round" they will have an increased border radius. If "rectangular" they will have no border radius. If "soft" they will have a soft border radius.
*/
"shape": 'round' | 'rectangular' | 'soft';
/**
* The size of the input boxes.
*/
"size": 'small' | 'medium' | 'large';
/**
* The type of input allowed in the input boxes.
*/
"type": 'text' | 'number';
/**
* The value of the input group.
*/
"value"?: string | number | null;
}
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
Expand Down Expand Up @@ -3404,6 +3469,10 @@ export interface IonInputCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonInputElement;
}
export interface IonInputOtpCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonInputOtpElement;
}
export interface IonItemOptionsCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonItemOptionsElement;
Expand Down Expand Up @@ -3933,6 +4002,27 @@ declare global {
prototype: HTMLIonInputElement;
new (): HTMLIonInputElement;
};
interface HTMLIonInputOtpElementEventMap {
"ionInput": InputOtpInputEventDetail;
"ionChange": InputOtpChangeEventDetail;
"ionComplete": InputOtpCompleteEventDetail;
"ionBlur": FocusEvent;
"ionFocus": FocusEvent;
}
interface HTMLIonInputOtpElement extends Components.IonInputOtp, HTMLStencilElement {
addEventListener<K extends keyof HTMLIonInputOtpElementEventMap>(type: K, listener: (this: HTMLIonInputOtpElement, ev: IonInputOtpCustomEvent<HTMLIonInputOtpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLIonInputOtpElementEventMap>(type: K, listener: (this: HTMLIonInputOtpElement, ev: IonInputOtpCustomEvent<HTMLIonInputOtpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLIonInputOtpElement: {
prototype: HTMLIonInputOtpElement;
new (): HTMLIonInputOtpElement;
};
interface HTMLIonInputPasswordToggleElement extends Components.IonInputPasswordToggle, HTMLStencilElement {
}
var HTMLIonInputPasswordToggleElement: {
Expand Down Expand Up @@ -4792,6 +4882,7 @@ declare global {
"ion-infinite-scroll": HTMLIonInfiniteScrollElement;
"ion-infinite-scroll-content": HTMLIonInfiniteScrollContentElement;
"ion-input": HTMLIonInputElement;
"ion-input-otp": HTMLIonInputOtpElement;
"ion-input-password-toggle": HTMLIonInputPasswordToggleElement;
"ion-item": HTMLIonItemElement;
"ion-item-divider": HTMLIonItemDividerElement;
Expand Down Expand Up @@ -6178,6 +6269,80 @@ declare namespace LocalJSX {
*/
"value"?: string | number | null;
}
interface IonInputOtp {
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
"autocapitalize"?: string;
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* If `true`, the user cannot interact with the input.
*/
"disabled"?: boolean;
/**
* The fill for the input boxes. If `"solid"` the input boxes will have a background. If `"outline"` the input boxes will be transparent with a border.
*/
"fill"?: 'outline' | 'solid';
/**
* A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. For numbers (type="number"): "numeric" For text (type="text"): "text"
*/
"inputmode"?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
/**
* The number of input boxes to display.
*/
"length"?: number;
/**
* Emitted when the input group loses focus.
*/
"onIonBlur"?: (event: IonInputOtpCustomEvent<FocusEvent>) => void;
/**
* The `ionChange` event is fired when the user modifies the input's value. Unlike the `ionInput` event, the `ionChange` event is only fired when changes are committed, not as the user types. The `ionChange` event fires when the `<ion-input-otp>` component loses focus after its value has changed. This event will not emit when programmatically setting the `value` property.
*/
"onIonChange"?: (event: IonInputOtpCustomEvent<InputOtpChangeEventDetail>) => void;
/**
* Emitted when all input boxes have been filled with valid values.
*/
"onIonComplete"?: (event: IonInputOtpCustomEvent<InputOtpCompleteEventDetail>) => void;
/**
* Emitted when the input group has focus.
*/
"onIonFocus"?: (event: IonInputOtpCustomEvent<FocusEvent>) => void;
/**
* The `ionInput` event is fired each time the user modifies the input's value. Unlike the `ionChange` event, the `ionInput` event is fired for each alteration to the input's value. This typically happens for each keystroke as the user types. For elements that accept text input (`type=text`, `type=tel`, etc.), the interface is [`InputEvent`](https://developer.mozilla.org/en-US/docs/Web/API/InputEvent); for others, the interface is [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event). If the input is cleared on edit, the type is `null`.
*/
"onIonInput"?: (event: IonInputOtpCustomEvent<InputOtpInputEventDetail>) => void;
/**
* A regex pattern string for allowed characters. Defaults based on type. For numbers (`type="number"`): `"[\p{N}]"` For text (`type="text"`): `"[\p{L}\p{N}]"`
*/
"pattern"?: string;
/**
* If `true`, the user cannot modify the value.
*/
"readonly"?: boolean;
/**
* Where separators should be shown between input boxes. Can be a comma-separated string or an array of numbers. For example: `"3"` will show a separator after the 3rd input box. `[1,4]` will show a separator after the 1st and 4th input boxes. `"all"` will show a separator between every input box.
*/
"separators"?: 'all' | string | number[];
/**
* The shape of the input boxes. If "round" they will have an increased border radius. If "rectangular" they will have no border radius. If "soft" they will have a soft border radius.
*/
"shape"?: 'round' | 'rectangular' | 'soft';
/**
* The size of the input boxes.
*/
"size"?: 'small' | 'medium' | 'large';
/**
* The type of input allowed in the input boxes.
*/
"type"?: 'text' | 'number';
/**
* The value of the input group.
*/
"value"?: string | number | null;
}
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
Expand Down Expand Up @@ -8309,6 +8474,7 @@ declare namespace LocalJSX {
"ion-infinite-scroll": IonInfiniteScroll;
"ion-infinite-scroll-content": IonInfiniteScrollContent;
"ion-input": IonInput;
"ion-input-otp": IonInputOtp;
"ion-input-password-toggle": IonInputPasswordToggle;
"ion-item": IonItem;
"ion-item-divider": IonItemDivider;
Expand Down Expand Up @@ -8411,6 +8577,7 @@ declare module "@stencil/core" {
"ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollElement>;
"ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollContentElement>;
"ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes<HTMLIonInputElement>;
"ion-input-otp": LocalJSX.IonInputOtp & JSXBase.HTMLAttributes<HTMLIonInputOtpElement>;
"ion-input-password-toggle": LocalJSX.IonInputPasswordToggle & JSXBase.HTMLAttributes<HTMLIonInputPasswordToggleElement>;
"ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes<HTMLIonItemElement>;
"ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes<HTMLIonItemDividerElement>;
Expand Down
23 changes: 23 additions & 0 deletions core/src/components/input-otp/input-otp-interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Values are converted to strings when emitted which is
* why we do not have a `number` type here even though the
* `value` prop accepts a `number` type.
*/
export interface InputOtpInputEventDetail {
value?: string | null;
event?: Event;
}
export interface InputOtpChangeEventDetail {
value?: string | null;
event?: Event;
}

export interface InputOtpCompleteEventDetail {
value?: string | null;
event?: Event;
}

export interface InputOtpCustomEvent<T = InputOtpChangeEventDetail> extends CustomEvent {
detail: T;
target: HTMLIonInputOtpElement;
}
20 changes: 20 additions & 0 deletions core/src/components/input-otp/input-otp.ios.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@import "./input-otp";
@import "../../themes/ionic.globals.ios";

// iOS Input OTP
// --------------------------------------------------

:host {
--border-width: #{$hairlines-width};
}

:host(.has-focus) .native-input:focus {
--border-width: 1px;
}
Comment on lines +7 to +13
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These borders will only be visible on devices that support hairline (half pixel) border widths


// Fills
// --------------------------------------------------

:host(.input-otp-fill-outline) {
--border-color: #{$item-ios-border-color};
}
Loading
Loading