Skip to content

Commit 1a2e8fd

Browse files
sean-perkinsmapsandappsliamdebeasi
authored
docs(autofocus): playground examples for setFocus (#3258)
--------- Co-authored-by: Shawn Taylor <[email protected]> Co-authored-by: Liam DeBeasi <[email protected]>
1 parent faffcda commit 1a2e8fd

File tree

8 files changed

+360
-0
lines changed

8 files changed

+360
-0
lines changed

docs/developing/managing-focus.md

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
---
2+
title: Managing Focus
3+
---
4+
5+
import Tabs from '@theme/Tabs';
6+
import TabItem from '@theme/TabItem';
7+
8+
<head>
9+
<title>Managing Focus</title>
10+
<meta
11+
name="description"
12+
content="Learn how to manage focus in Ionic applications using the setFocus API instead of the autofocus attribute."
13+
/>
14+
</head>
15+
16+
Ionic provides a `setFocus` API on components such as [Input](../api/input), [Searchbar](../api/searchbar), and [Textarea](../api/textarea) that allows developers to manually set focus to an element. This API should be used in place of the `autofocus` attribute and called within:
17+
18+
- The `ionViewDidEnter` lifecycle event for routing applications when a page is entered.
19+
- The `didPresent` lifecycle event for overlays when an overlay is presented.
20+
- The `appload` event for vanilla JavaScript applications when the application loads.
21+
- The result of a user gesture or interaction.
22+
23+
## Why not autofocus?
24+
25+
The `autofocus` attribute is a standard HTML attribute that allows developers to set focus to an element when a page loads. This attribute is commonly used to set focus to the first input element on a page. However, the `autofocus` attribute can cause issues in routing applications when navigating between pages. This is because the `autofocus` attribute will set focus to the element when the page loads, but will not set focus to the element when the page is revisited. Learn more about the `autofocus` attribute in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus).
26+
27+
## Platform Restrictions
28+
29+
There are platform restrictions you should be aware of when using the `setFocus` API, including:
30+
31+
1. Android requires user interaction before setting focus to an element. This can be as simple as a user tapping on the screen.
32+
2. Interactive elements can only focused a result of a user gesture on Mobile Safari (iOS), such as calling `setFocus` as the result of a button click.
33+
34+
## Basic Usage
35+
36+
The example below demonstrates how to use the `setFocus` API to request focus on an input when the user clicks a button.
37+
38+
import Basic from '@site/static/usage/v7/input/set-focus/index.md';
39+
40+
<Basic />
41+
42+
## Routing
43+
44+
Developers can use the `ionViewDidEnter` lifecycle event to set focus to an element when a page is entered.
45+
46+
````mdx-code-block
47+
<Tabs
48+
groupId="framework"
49+
defaultValue="angular"
50+
values={[
51+
{ value: 'angular', label: 'Angular' },
52+
{ value: 'react', label: 'React' },
53+
{ value: 'vue', label: 'Vue' },
54+
]
55+
}>
56+
57+
<TabItem value="angular">
58+
59+
```ts
60+
/* example.component.ts */
61+
import { Component, ViewChild } from '@angular/core';
62+
import { IonInput } from '@ionic/angular';
63+
64+
@Component({
65+
selector: 'app-example',
66+
templateUrl: './example.component.html',
67+
})
68+
export class ExampleComponent {
69+
@ViewChild('input') input!: IonInput;
70+
71+
ionViewDidEnter() {
72+
this.input.setFocus();
73+
}
74+
}
75+
```
76+
</TabItem>
77+
<TabItem value="react">
78+
79+
```tsx
80+
import React, { useRef } from 'react';
81+
import { IonInput, IonPage, useIonViewDidEnter } from '@ionic/react';
82+
83+
const Home = () => {
84+
const input = useRef<HTMLIonInputElement>(null);
85+
86+
useIonViewDidEnter(() => {
87+
input.current?.setFocus();
88+
});
89+
90+
return (
91+
<IonPage>
92+
<IonInput ref={input} label="setFocus" labelPlacement="floating"></IonInput>
93+
</IonPage>
94+
);
95+
};
96+
97+
export default Home;
98+
```
99+
100+
</TabItem>
101+
<TabItem value="vue">
102+
103+
```html
104+
<template>
105+
<ion-page>
106+
<ion-input ref="input" label="setFocus" label-placement="floating"></ion-input>
107+
</ion-page>
108+
</template>
109+
110+
<script setup lang="ts">
111+
import { IonInput, IonPage, onIonViewDidEnter } from '@ionic/vue';
112+
import { ref } from 'vue';
113+
114+
const input = ref();
115+
onIonViewDidEnter(() => {
116+
requestAnimationFrame(() => {
117+
// requestAnimationFrame is currently required due to:
118+
// https://github.com/ionic-team/ionic-framework/issues/24434
119+
input.value.$el.setFocus();
120+
});
121+
});
122+
</script>
123+
```
124+
125+
</TabItem>
126+
</Tabs>
127+
````
128+
129+
## Overlays
130+
131+
Developers can use the `didPresent` lifecycle event to set focus to an element when an overlay is presented.
132+
133+
````mdx-code-block
134+
<Tabs
135+
groupId="framework"
136+
defaultValue="javascript"
137+
values={[
138+
{ value: 'javascript', label: 'Javascript' },
139+
{ value: 'angular', label: 'Angular' },
140+
{ value: 'react', label: 'React' },
141+
{ value: 'vue', label: 'Vue' },
142+
]
143+
}>
144+
145+
<TabItem value="javascript">
146+
147+
```html
148+
<ion-modal>
149+
<ion-input></ion-input>
150+
</ion-modal>
151+
152+
<script>
153+
const modal = document.querySelector('ion-modal');
154+
modal.addEventListener('didPresent', () => {
155+
const input = modal.querySelector('ion-input');
156+
input.setFocus();
157+
});
158+
</script>
159+
```
160+
161+
</TabItem>
162+
163+
<TabItem value="angular">
164+
165+
```ts
166+
/* example.component.ts */
167+
import { Component, ViewChild } from '@angular/core';
168+
import { IonInput } from '@ionic/angular';
169+
170+
@Component({
171+
selector: 'app-example',
172+
templateUrl: './example.component.html',
173+
})
174+
export class ExampleComponent {
175+
@ViewChild('input') input!: IonInput;
176+
177+
onDidPresent() {
178+
this.input.setFocus();
179+
}
180+
}
181+
```
182+
183+
```html
184+
<!-- example.component.html -->
185+
<ion-modal (didPresent)="onDidPresent()">
186+
<ion-input #input></ion-input>
187+
</ion-modal>
188+
```
189+
190+
</TabItem>
191+
<TabItem value="react">
192+
193+
```tsx
194+
import React, { useRef } from 'react';
195+
import { IonInput, IonModal } from '@ionic/react';
196+
197+
const Home = () => {
198+
const input = useRef<HTMLIonInputElement>(null);
199+
200+
const onDidPresent = () => {
201+
input.current?.setFocus();
202+
};
203+
204+
return (
205+
<IonModal onDidPresent={onDidPresent}>
206+
<IonInput ref={input}></IonInput>
207+
</IonModal>
208+
);
209+
};
210+
211+
export default Home;
212+
```
213+
214+
</TabItem>
215+
<TabItem value="vue">
216+
217+
```html
218+
<template>
219+
<ion-modal @didPresent="onDidPresent">
220+
<ion-input ref="input"></ion-input>
221+
</ion-modal>
222+
</template>
223+
224+
<script setup lang="ts">
225+
import { IonInput, IonModal } from '@ionic/vue';
226+
import { ref } from 'vue';
227+
228+
const input = ref();
229+
230+
function onDidPresent() {
231+
input.value.$el.setFocus();
232+
}
233+
</script>
234+
```
235+
236+
</TabItem>
237+
</Tabs>
238+
````

sidebars.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module.exports = {
2626
'developing/hardware-back-button',
2727
'developing/keyboard',
2828
'developing/config',
29+
'developing/managing-focus',
2930
],
3031
},
3132
{
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
```html
2+
<ion-list>
3+
<ion-item>
4+
<ion-button (click)="input.setFocus()">Click to set focus</ion-button>
5+
</ion-item>
6+
<ion-item>
7+
<ion-input #input label="Email" labelPlacement="floating"></ion-input>
8+
</ion-item>
9+
</ion-list>
10+
```
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>setFocus</title>
7+
<link rel="stylesheet" href="../../../common.css" />
8+
<script src="../../../common.js"></script>
9+
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core@7/dist/ionic/ionic.esm.js"></script>
10+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core@7/css/ionic.bundle.css" />
11+
</head>
12+
13+
<body>
14+
<ion-app>
15+
<ion-content>
16+
<ion-list>
17+
<ion-item>
18+
<ion-button onclick="setFocus()">Click to set focus</ion-button>
19+
</ion-item>
20+
<ion-item>
21+
<ion-input label="Email" label-placement="floating"></ion-input>
22+
</ion-item>
23+
</ion-list>
24+
</ion-content>
25+
</ion-app>
26+
<script>
27+
function setFocus() {
28+
const input = document.querySelector('ion-input');
29+
input.setFocus();
30+
}
31+
</script>
32+
</body>
33+
</html>
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Playground from '@site/src/components/global/Playground';
2+
3+
import javascript from './javascript.md';
4+
import angular from './angular.md';
5+
import vue from './vue.md';
6+
import react from './react.md';
7+
8+
<Playground
9+
version="7"
10+
code={{
11+
javascript,
12+
vue,
13+
angular,
14+
react,
15+
}}
16+
src="usage/v7/input/set-focus/demo.html"
17+
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
```html
2+
<ion-list>
3+
<ion-item>
4+
<ion-button onclick="setFocus()">Click to set focus</ion-button>
5+
</ion-item>
6+
<ion-item>
7+
<ion-input label="Email" label-placement="floating"></ion-input>
8+
</ion-item>
9+
</ion-list>
10+
11+
<script>
12+
function setFocus() {
13+
const input = document.querySelector('ion-input');
14+
input.setFocus();
15+
}
16+
</script>
17+
```
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
```tsx
2+
import React, { useRef } from 'react';
3+
import { IonInput, IonItem, IonList, IonButton } from '@ionic/react';
4+
5+
const Home = () => {
6+
const input = useRef<HTMLIonInputElement>(null);
7+
8+
return (
9+
<IonList>
10+
<IonItem>
11+
<IonButton onClick={() => input.current?.setFocus()}>Click to set focus</IonButton>
12+
</IonItem>
13+
<IonItem>
14+
<IonInput ref={input} label="Email" labelPlacement="floating"></IonInput>
15+
</IonItem>
16+
</IonList>
17+
);
18+
};
19+
20+
export default Home;
21+
```
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
```html
2+
<template>
3+
<ion-list>
4+
<ion-item>
5+
<ion-button @click="setFocus">Click to set focus</ion-button>
6+
</ion-item>
7+
<ion-item>
8+
<ion-input ref="input" label="Email" label-placement="floating"></ion-input>
9+
</ion-item>
10+
</ion-list>
11+
</template>
12+
13+
<script setup lang="ts">
14+
import { IonInput, IonItem, IonList, IonButton } from '@ionic/vue';
15+
import { ref } from 'vue';
16+
17+
const input = ref();
18+
19+
function setFocus() {
20+
input.value.$el.setFocus();
21+
}
22+
</script>
23+
```

0 commit comments

Comments
 (0)