Swipeable row Gagan

Transaction row with swipe-left gesture to reveal edit and delete actions. Uses pointer events for cross-platform gesture handling โ€” works on touch and mouse. Reveals 128px of action buttons. Used in the expense list to give power users a fast edit/delete path without tapping into the detail view.

Default โ€” closed

A ๐Ÿœ
Farzi Cafe โ€” dinner
paid by Aarav ยท yesterday
โ‚น2,400

Swipe left to reveal actions. Actions are hidden behind the surface until triggered.

Revealed โ€” swiped left

A ๐Ÿœ
Farzi Cafe โ€” dinner
paid by Aarav ยท yesterday
โ‚น2,400

Surface translateX(-128px). Edit action (butter) on left, delete action (coral) on right. Tapping anywhere on the surface snaps it back to closed.

In a list

A๐Ÿœ
Farzi Cafe โ€” dinner
paid by Aaravยทyesterday
โ‚น2,400
R๐Ÿ 
Flat rent โ€” June
paid by Rohanยท3 days ago
โ‚น18,000
K๐Ÿ›’
Swiggy order โ€” Kabir
paid by Kabirยท1 week ago
โ‚น840

Usage

Do Only one row can be revealed at a time. When a user starts swiping a new row, close any previously revealed row before revealing the new one. This prevents the list from becoming a mess of half-swiped rows.
Don't Don't use swipeable row in contexts where the user might be scrolling horizontally (e.g. inside a horizontal scroll container). The swipe gesture will conflict with scroll. In those contexts, use a long-press context menu instead.
Do Use pointer events, not touch events. Pointer events fire on both touch and mouse, enabling mouse users to drag-reveal on desktop. Set touch-action: pan-y on the swipe surface so vertical scrolling still works while the gesture handler captures horizontal movement.
Don't Don't perform delete directly when the delete button is tapped โ€” show a confirmation (a bottom sheet or inline undo toast). Deletion without undo is a UX violation, especially for settled expenses that can't be recovered.

Spec

PropertyValueNotes
Reveal width128pxTotal โ€” 64px edit + 64px delete
Reveal threshold45% of reveal width (~58px)Snap open if swipe exceeds threshold; snap closed if below
Gesture typePointer eventsNot touch events โ€” works on desktop + touch
Surface animation240ms ease-out--d-med, --ease-out
DirectionLeft onlyRight swipe has no action
Edit action color--butterAmber โ€” non-destructive
Delete action color--coralRed โ€” destructive, requires confirm
Close on outside tapYesTap anywhere on the surface to snap closed
Close on scrollYesVertical scroll should close any open row

Accessibility

Swipe gesture alternative Swipe is a gesture-only interaction โ€” not accessible to keyboard or switch users. Provide an accessible alternative: a context menu triggered by long-press or a three-dot button within the row. The swipe actions (edit, delete) must be reachable without gesture.
Action button labels Action buttons say "edit" and "delete" โ€” that's not enough context when multiple rows exist. Add aria-label: aria-label="Edit Farzi Cafe dinner" and aria-label="Delete Farzi Cafe dinner".

Code

HTML

<div class="swipe-container">
  <!-- Actions revealed on swipe -->
  <div class="swipe-actions" aria-hidden="true">
    <button class="swipe-action-edit"
            aria-label="Edit Farzi Cafe dinner">edit</button>
    <button class="swipe-action-delete"
            aria-label="Delete Farzi Cafe dinner">delete</button>
  </div>
  <!-- Swipe surface -->
  <div class="swipe-surface" style="touch-action: pan-y;">
    <!-- avatar, body, price cells ... -->
  </div>
</div>

Design tokens used

TokenValueRole
--butter#F4C94EEdit action background
--coral#E76F51Delete action background
--s-paper#FBF8F0Row surface background
--ink-line#DDD2B8Container border
--teal#0E7C66Positive share amount
--d-med240msSnap animation duration
--ease-outcubic-bezier(0.23,1,0.32,1)Snap easing
--r-md14pxContainer border radius

See it in context

Interactive prototype โ€” this component is live below. Tap, swipe, and drag to explore.

Swipe any transaction row to the left to reveal the edit/delete action buttons. The row rubber-bands if you release before the threshold.