Skip to content

Commit 5d201bd

Browse files
authored
feat(modal): default handleBehavior to "cycle" for sheet modals (#31222)
Issue number: resolves internal
1 parent bd21e00 commit 5d201bd

6 files changed

Lines changed: 35 additions & 11 deletions

File tree

BREAKING.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
1919
- [Components](#version-9x-components)
2020
- [Input](#version-9x-input)
2121
- [Legacy Picker](#version-9x-legacy-picker)
22+
- [Modal](#version-9x-modal)
2223
- [Router Outlet](#version-9x-router-outlet)
2324
- [Searchbar](#version-9x-searchbar)
2425
- [Select](#version-9x-select)
@@ -73,6 +74,16 @@ The string form no longer behaves the same way. Because an HTML attribute coerce
7374
- Remove any usages of `pickerController`. If using React, remove any usages of the `useIonPicker` hook. These controller-based APIs have been removed. Use the inline picker component instead.
7475
- Remove any usages of the `PickerOptions`, `PickerButton`, `PickerColumn`, and `PickerColumnOption` type exports. These types were associated with the legacy picker and have been removed.
7576

77+
<h4 id="version-9x-modal">Modal</h4>
78+
79+
The `handleBehavior` property on `ion-modal` now defaults to `"cycle"` instead of `"none"`. For sheet modals that display a handle, this means the handle is now focusable and activating it (by click, keyboard, or screen reader) cycles the sheet through its available breakpoints. This matches the native iOS sheet behavior and keeps sheet modals operable for assistive technology users by default.
80+
81+
Sheet modals that relied on the handle being inert should set `handleBehavior="none"` to restore the previous behavior:
82+
83+
```html
84+
<ion-modal handle-behavior="none"></ion-modal>
85+
```
86+
7687
<h4 id="version-9x-router-outlet">Router Outlet</h4>
7788

7889
`ion-router-outlet` now exposes a `swipeGesture` property that controls the swipe-to-go-back gesture per outlet. This property defaults to `true` in `"ios"` mode and `false` in `"md"` mode.

core/api.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ ion-modal,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefin
11671167
ion-modal,prop,expandToScroll,boolean,true,false,false
11681168
ion-modal,prop,focusTrap,boolean,true,false,false
11691169
ion-modal,prop,handle,boolean | undefined,undefined,false,false
1170-
ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'none',false,false
1170+
ion-modal,prop,handleBehavior,"cycle" | "none" | undefined,'cycle',false,false
11711171
ion-modal,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
11721172
ion-modal,prop,initialBreakpoint,number | undefined,undefined,false,false
11731173
ion-modal,prop,isOpen,boolean,false,false,false

core/src/components.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,8 +2003,8 @@ export namespace Components {
20032003
*/
20042004
"handle"?: boolean;
20052005
/**
2006-
* The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal).
2007-
* @default 'none'
2006+
* The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`.
2007+
* @default 'cycle'
20082008
*/
20092009
"handleBehavior"?: ModalHandleBehavior;
20102010
/**
@@ -7152,8 +7152,8 @@ declare namespace LocalJSX {
71527152
*/
71537153
"handle"?: boolean;
71547154
/**
7155-
* The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal).
7156-
* @default 'none'
7155+
* The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`.
7156+
* @default 'cycle'
71577157
*/
71587158
"handleBehavior"?: ModalHandleBehavior;
71597159
/**

core/src/components/modal/modal.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,20 @@ export class Modal implements ComponentInterface, OverlayInterface {
202202
/**
203203
* The interaction behavior for the sheet modal when the handle is pressed.
204204
*
205-
* Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed.
206-
* Set to `"cycle"` to let the modal cycle between available breakpoints when pressed.
205+
* Handle behavior is unavailable when the `handle` property is set to
206+
* `false` or when the `breakpoints` property is not set (using a
207+
* fullscreen or card modal).
207208
*
208-
* Handle behavior is unavailable when the `handle` property is set to `false` or
209-
* when the `breakpoints` property is not set (using a fullscreen or card modal).
209+
* Set to `"cycle"` to make the handle focusable and let the sheet modal
210+
* cycle between available breakpoints when pressed. This keeps the sheet
211+
* operable with assistive technology.
212+
*
213+
* Set to `"none"` to make the handle purely decorative when pressed and
214+
* removed from the tab order.
215+
*
216+
* Defaults to `"cycle"`.
210217
*/
211-
@Prop() handleBehavior?: ModalHandleBehavior = 'none';
218+
@Prop() handleBehavior?: ModalHandleBehavior = 'cycle';
212219

213220
/**
214221
* The component to display inside of the modal.

core/src/components/modal/test/sheet/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@
133133
>
134134
Present Sheet Modal (HandleBehavior: Cycle)
135135
</button>
136+
<button
137+
id="handle-behavior-none-modal"
138+
onclick="presentModal({ handleBehavior: 'none', initialBreakpoint: 0.25, breakpoints: [0, 0.25, 0.5, 0.75, 1] })"
139+
>
140+
Present Sheet Modal (HandleBehavior: None)
141+
</button>
136142
<button id="custom-handle-modal" onclick="presentModal({ cssClass: 'custom-handle' })">
137143
Present Sheet Modal (Custom Handle)
138144
</button>

core/src/components/modal/test/sheet/modal.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
264264
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
265265
const modal = page.locator('ion-modal');
266266

267-
await page.click('#sheet-modal');
267+
await page.click('#handle-behavior-none-modal');
268268
await ionModalDidPresent.next();
269269

270270
const handle = page.locator('ion-modal .modal-handle');

0 commit comments

Comments
 (0)