A modifier that handles press interactions across mouse, touch, keyboard, and screen readers. It normalizes press events across browsers and platforms, and handles many nuances of dealing with pointer and keyboard events.
import { press } from 'frontile';
press listens to user pointer and keyboard input rather than native click
events, so calling element.click() programmatically does not trigger
onPress. A disabled native form control cannot be pressed by a user.
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { press, type PressEvent } from 'frontile';
export default class PressExample extends Component {
@tracked events = [];
@tracked isPressed = false;
handlePressStart = (e: PressEvent) => {
this.events = [...this.events, `press start with ${e.pointerType}`];
};
handlePressEnd = (e: PressEvent) => {
this.events = [...this.events, `press end with ${e.pointerType}`];
};
handlePress = (e: PressEvent) => {
this.events = [...this.events, `press with ${e.pointerType}`];
};
handlePressChange = (isPressed) => {
this.isPressed = isPressed;
};
<template>
<div class='flex items-center space-x-2'>
<button
type='button'
{{press
onPressStart=this.handlePressStart
onPressEnd=this.handlePressEnd
onPress=this.handlePress
onPressChange=this.handlePressChange
}}
class='rounded bg-success p-4 text-on-success transition-transform data-[pressed=true]:scale-95'
data-pressed={{this.isPressed}}
>
Press me! ({{if this.isPressed 'pressed' 'not pressed'}})
</button>
<div
class='w-48 h-48 overflow-auto mt-4 space-y-1 border border-neutral-subtle rounded p-2'
>
Output:
<ul>
{{#each this.events as |event index|}}
<li class='text-sm'>{{event}}</li>
{{/each}}
</ul>
</div>
</div>
</template>
}
onPress as the first argument: {{press this.handlePress}}onPress with named arguments for other callbacksonPress (assertion error)onPressChange also needs
pointercancel)<button type="button"> press also calls preventDefault(), which suppresses the
browser's native activation click, so the element fires a single press per keypresscontinuePropagation() on the PressEvent in
any handler to let it through. Only events on the pressed element itself are
stopped - a release that happens outside of the element is left untouched, so
other listeners on the page (including document-level ones) still receive it.Note:
preventDefault()on the keyboard event does not stop it propagating. An ancestorkeydownhandler that also treats Enter or Space as activation will act on the same keypress a second time — a calendar grid handling Enter to select the focused day selects twice once its day cells usepress. Container-level key handlers above a press-bearing element should checkevent.defaultPreventedbefore acting.
Apply press to a natively interactive element such as a button whenever
possible. The modifier normalizes Enter and Space activation, but it does not
add a role, accessible name, focusability, or disabled semantics to a generic
element. If a custom element is unavoidable, provide those semantics yourself.
On a native button, set type="button" unless the press should submit its form.
Disabled behavior comes from the native disabled attribute; the modifier does
not infer disabled state from styling or aria-disabled alone.
The press modifier accepts an optional positional onPress function and the following named options:
| Name | Type | Description |
|---|---|---|
onPress |
(e: PressEvent) => void |
Handler called when press is released over the target. |
onPressStart |
(e: PressEvent) => void |
Handler called when a press interaction starts. |
onPressEnd |
(e: PressEvent) => void |
Handler called when a press interaction ends, either over the target or when the pointer leaves the target. |
onPressUp |
(e: PressEvent) => void |
Handler called when a press is released over the target. Not called when the release happens outside of the target. |
onPressChange |
(isPressed: boolean) => void |
Handler called when the press state changes. |
Press events are normalized across different input methods and provide consistent information:
| Property | Type | Description |
|---|---|---|
type |
'pressstart' | 'pressend' | 'pressup' | 'press' |
The type of press event. |
pointerType |
'mouse' | 'pen' | 'touch' | 'keyboard' | 'virtual' |
The pointer type that triggered the event. |
target |
Element |
The target element of the press event. |
shiftKey |
boolean |
Whether the shift key was held during the event. |
ctrlKey |
boolean |
Whether the ctrl key was held during the event. |
metaKey |
boolean |
Whether the meta key was held during the event. |
altKey |
boolean |
Whether the alt key was held during the event. |
x |
number |
The x position relative to the target element. |
y |
number |
The y position relative to the target element. |
continuePropagation() |
() => void |
Allows the event to continue propagating to parent elements. |