diff --git a/docs/api/input.md b/docs/api/input.md
index 6bdecfc9568..55f469ff798 100644
--- a/docs/api/input.md
+++ b/docs/api/input.md
@@ -120,6 +120,26 @@ import FilteringData from '@site/static/usage/v7/input/filtering/index.md';
+## Input Masking
+
+Input masks are expressions that constrain input to support valid input values. Ionic recommends using [Maskito](https://tinkoff.github.io/maskito/getting-started/what-is-maskito) for input masking. Maskito is a lightweight, dependency-free library for masking input fields. It supports a wide range of masks, including phone numbers, credit cards, dates, and more.
+
+To get started with Maskito, install the library:
+
+```bash
+npm install @maskito/core @maskito/{angular,react,vue}
+```
+
+import Masking from '@site/static/usage/v7/input/mask/index.md';
+
+
+
+:::note
+
+Please submit bug reports with Maskito to the [Maskito Github repository](https://github.com/Tinkoff/maskito/issues). For technical support, please use the [Ionic Forum](https://forum.ionicframework.com/) or [Ionic Discord](http://chat.ionicframework.com/).
+
+:::
+
## Theming
### Colors
diff --git a/src/components/global/Playground/stackblitz.utils.ts b/src/components/global/Playground/stackblitz.utils.ts
index ad2947ba15b..f379a2d472c 100644
--- a/src/components/global/Playground/stackblitz.utils.ts
+++ b/src/components/global/Playground/stackblitz.utils.ts
@@ -183,6 +183,15 @@ const openReactEditor = async (code: string, options?: EditorOptions) => {
options.version
);
+ const package_json = JSON.parse(defaultFiles[4]);
+
+ if (options?.dependencies) {
+ package_json.dependencies = {
+ ...package_json.dependencies,
+ ...options.dependencies,
+ };
+ }
+
const appTsx = 'src/App.tsx';
const files = {
'public/index.html': defaultFiles[6],
@@ -191,7 +200,7 @@ const openReactEditor = async (code: string, options?: EditorOptions) => {
'src/main.tsx': code,
'src/theme/variables.css': defaultFiles[2],
'tsconfig.json': defaultFiles[3],
- 'package.json': defaultFiles[4],
+ 'package.json': JSON.stringify(package_json, null, 2),
'package-lock.json': defaultFiles[5],
...options?.files,
...options?.dependencies,
@@ -227,6 +236,15 @@ const openVueEditor = async (code: string, options?: EditorOptions) => {
options.version
);
+ const package_json = JSON.parse(defaultFiles[0]);
+
+ if (options?.dependencies) {
+ package_json.dependencies = {
+ ...package_json.dependencies,
+ ...options.dependencies,
+ };
+ }
+
const mainTs = 'src/main.ts';
const files = {
'src/App.vue': defaultFiles[6],
@@ -236,7 +254,7 @@ const openVueEditor = async (code: string, options?: EditorOptions) => {
'src/theme/variables.css': defaultFiles[3],
'index.html': defaultFiles[2],
'vite.config.ts': defaultFiles[4],
- 'package.json': defaultFiles[0],
+ 'package.json': JSON.stringify(package_json, null, 2),
'package-lock.json': defaultFiles[1],
'tsconfig.json': defaultFiles[7],
'tsconfig.node.json': defaultFiles[8],
diff --git a/static/usage/v7/input/mask/angular/app_module_ts.md b/static/usage/v7/input/mask/angular/app_module_ts.md
new file mode 100644
index 00000000000..653793d4262
--- /dev/null
+++ b/static/usage/v7/input/mask/angular/app_module_ts.md
@@ -0,0 +1,19 @@
+```ts
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { BrowserModule } from '@angular/platform-browser';
+
+import { IonicModule } from '@ionic/angular';
+
+import { AppComponent } from './app.component';
+import { ExampleComponent } from './example.component';
+
+import { MaskitoModule } from '@maskito/angular';
+
+@NgModule({
+ imports: [BrowserModule, FormsModule, MaskitoModule, IonicModule.forRoot({})],
+ declarations: [AppComponent, ExampleComponent],
+ bootstrap: [AppComponent],
+})
+export class AppModule {}
+```
diff --git a/static/usage/v7/input/mask/angular/example_component_html.md b/static/usage/v7/input/mask/angular/example_component_html.md
new file mode 100644
index 00000000000..f6d27b19558
--- /dev/null
+++ b/static/usage/v7/input/mask/angular/example_component_html.md
@@ -0,0 +1,20 @@
+```html
+
+
+
+
+
+
+
+
+```
diff --git a/static/usage/v7/input/mask/angular/example_component_ts.md b/static/usage/v7/input/mask/angular/example_component_ts.md
new file mode 100644
index 00000000000..2294a2e3403
--- /dev/null
+++ b/static/usage/v7/input/mask/angular/example_component_ts.md
@@ -0,0 +1,31 @@
+```ts
+import { Component } from '@angular/core';
+
+import { MaskitoOptions, MaskitoElementPredicateAsync } from '@maskito/core';
+
+@Component({
+ selector: 'app-example',
+ templateUrl: 'example.component.html',
+})
+export class ExampleComponent {
+ readonly phoneMask: MaskitoOptions = {
+ mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
+ };
+
+ readonly cardMask: MaskitoOptions = {
+ mask: [
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ],
+ };
+
+ readonly maskPredicate: MaskitoElementPredicateAsync = async (el) => (el as HTMLIonInputElement).getInputElement();
+}
+```
diff --git a/static/usage/v7/input/mask/demo.html b/static/usage/v7/input/mask/demo.html
new file mode 100644
index 00000000000..fc02f355ef7
--- /dev/null
+++ b/static/usage/v7/input/mask/demo.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Input
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/usage/v7/input/mask/index.md b/static/usage/v7/input/mask/index.md
new file mode 100644
index 00000000000..92ae30b967f
--- /dev/null
+++ b/static/usage/v7/input/mask/index.md
@@ -0,0 +1,58 @@
+import Playground from '@site/src/components/global/Playground';
+
+import javascript_index_html from './javascript/index_html.md';
+import javascript_index_ts from './javascript/index_ts.md';
+
+import react_main_tsx from './react.md';
+
+import vue_example_vue from './vue.md';
+
+import angular_app_module_ts from './angular/app_module_ts.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/v7/input/mask/javascript/index_html.md b/static/usage/v7/input/mask/javascript/index_html.md
new file mode 100644
index 00000000000..512a34ff9f5
--- /dev/null
+++ b/static/usage/v7/input/mask/javascript/index_html.md
@@ -0,0 +1,58 @@
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/static/usage/v7/input/mask/javascript/index_ts.md b/static/usage/v7/input/mask/javascript/index_ts.md
new file mode 100644
index 00000000000..89d38873488
--- /dev/null
+++ b/static/usage/v7/input/mask/javascript/index_ts.md
@@ -0,0 +1,28 @@
+```ts
+import { defineCustomElements } from '@ionic/core/loader';
+
+import { Maskito } from '@maskito/core';
+
+/* Core CSS required for Ionic components to work properly */
+import '@ionic/core/css/core.css';
+
+/* Basic CSS for apps built with Ionic */
+import '@ionic/core/css/normalize.css';
+import '@ionic/core/css/structure.css';
+import '@ionic/core/css/typography.css';
+
+/* Optional CSS utils that can be commented out */
+import '@ionic/core/css/padding.css';
+import '@ionic/core/css/float-elements.css';
+import '@ionic/core/css/text-alignment.css';
+import '@ionic/core/css/text-transformation.css';
+import '@ionic/core/css/flex-utils.css';
+import '@ionic/core/css/display.css';
+
+/* Theme variables */
+import './theme/variables.css';
+
+defineCustomElements();
+
+(window as any).Maskito = Maskito;
+```
diff --git a/static/usage/v7/input/mask/react.md b/static/usage/v7/input/mask/react.md
new file mode 100644
index 00000000000..dd22df29914
--- /dev/null
+++ b/static/usage/v7/input/mask/react.md
@@ -0,0 +1,55 @@
+```tsx
+import React from 'react';
+import { IonInput, IonItem, IonList } from '@ionic/react';
+import { useMaskito } from '@maskito/react';
+
+function Example() {
+ const cardMask = useMaskito({
+ options: {
+ mask: [
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ' ',
+ ...Array(4).fill(/\d/),
+ ],
+ },
+ });
+
+ const phoneMask = useMaskito({
+ options: {
+ mask: ['+', '1', ' ', '(', /\d/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/],
+ },
+ });
+
+ return (
+
+
+ {
+ if (cardRef) {
+ cardMask(await cardRef.getInputElement());
+ }
+ }}
+ label="Card number"
+ placeholder="0000 0000 0000 0000"
+ >
+
+
+ {
+ if (phoneInput) {
+ phoneMask(await phoneInput.getInputElement());
+ }
+ }}
+ label="US phone number"
+ placeholder="+1 (xxx) xxx-xxxx"
+ >
+
+
+ );
+}
+export default Example;
+```
diff --git a/static/usage/v7/input/mask/vue.md b/static/usage/v7/input/mask/vue.md
new file mode 100644
index 00000000000..40c19079565
--- /dev/null
+++ b/static/usage/v7/input/mask/vue.md
@@ -0,0 +1,49 @@
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```