Angular Native
DocsLearnExamplesGitHubSponsor
Build a habit tracker

4. Touch

A phone has no click. A finger goes down, may move, and comes up, and the responder system decides which view the touch belongs to. <pressable> is the view that takes part in that: it claims the touch, works out with nested controls and scrolling ancestors which of them keeps it, and emits press when a short touch ends without being cancelled.

Step 1 of 3

Tick a habit off

Make each card a <pressable>, import Pressable, and flip the habit in the signal when it is pressed:

<pressable class="habit" accessibilityRole="button" (press)="toggle(habit.id)">
  ...
</pressable>
protected toggle(id: string): void {
  this.habits.update((habits) =>
    habits.map((habit) => (habit.id === id ? { ...habit, done: !habit.done } : habit)),
  );
}

Toggling by id rather than name is what keeps this correct once two habits can share a name: matching on name would flip every habit called the same thing at once.

accessibilityRole="button" is what VoiceOver and TalkBack announce, and what a screen reader user can activate: there is no <button> element to carry the role, so the pressable says it.

A touch that wanders too far before lifting is cancelled, and is not a press. How far it may go is pressRetentionOffset, which reaches past the card's visible edge, so crossing the edge does not cancel the press straight away. A touch held past the long-press delay emits longPress instead of press.