Docs
Lists

Swipe Action Row

Any row in a glass card whose swipe actions bud out as tinted bubbles, with a full swipe that commits and one row open at a time.

$npx swiftpieces add SwipeActionRow
Try it in the Playground Use it on a real screen, take it apart, remix it, and copy the SwiftUI. No account needed.
Free · MIT + Commons ClauseiOS 17.0+Liquid Glasslistswipegestureactionsglass
Type
SwipeActionRow
Files
SwipeActionRow.swift
Depends on
Nothing (Apple frameworks only)
Version
2.2.0
In a full screen · SwiftPieces ProActivityAccount activity grouped by day, with rows that swipe to categorize, split or hide.

Row with swipe-to-reveal actions that works in a plain VStack or ScrollView, not only in List. The row is a liquid glass card and its actions are tinted glass bubbles. As the card slides they bud out of its edge and rest joined to it and to each other, so the open row is one liquid surface; closing, they melt back in.

Notes

  • The row is a liquid glass card (26pt continuous radius) and its actions are tinted glass bubbles with dark ink, style.tileGap (6pt) from the card and from each other. That gap sits inside the liquid merge distance, so an open row is one liquid surface: card and bubbles held together by necks. Pass light tints as tint; the house uses signal (#FF0000) for the one destructive or primary action and butter for a warning-like one such as snooze. On iOS 26 this is Liquid Glass; before that the same shapes draw as frosted Material, and under Reduce Transparency as solid fills.
  • Drags are only claimed when they start horizontally, so the enclosing ScrollView keeps vertical scrolling. The card stays under your finger. The row clips sideways, and the clip fades out over a short distance past each edge, so the glass's shadow is never cut by a hard line and a card slid past the edge slips away under the fade. A drag the system cancels (a scroll that takes over) lands the card in the nearest position and fires nothing.
  • Letting go keeps the card's speed: it settles into the open bubbles with a visible give, more the harder you flick, though never more than about a sixth of its travel past them, and a drag that closes comes home firmly. Tapping the card or a bubble, or opening and closing through the open binding, snaps it into place with a smaller give. Whether it opens or closes still depends on where the flick would carry it. Grabbing a card that is still landing never jumps: it finishes landing under your finger over the first tenth of a second.
  • Bubbles bud out of the card's edge: each is born just inside it, shrunk, where the two are one shape, and the reveal draws it out to its slot at the row's edge, pulling a neck as it goes. The edge bubble leads and each one further in follows a step behind, all driven by the card's place, so they never trail the finger and bud and melt exactly with the card when it springs. A bubble's color fills in as it clears the card and drains as it heads home; its glyph and label arrive once it is clear and blur away the moment the card heads home, so nothing ever sits on the card's glass. Opened past their slots, the bubbles stretch to fill the gap. A pressed bubble sinks a few points, glass and glyph together.
  • A full swipe (past 60% of the row width, and never less than two bubbles) clicks in like a detent: the other bubbles melt into the edge bubble as it swells across the whole bar, its glyph bounces once and a rigid impact fires as it arms, never as it lets go. Drag back before letting go and they bud out of it again. Past that line the card moves against rubber-band resistance; where the open bubbles reach further (several actions, or a narrow row), the resistance starts at them instead. Releasing runs that action. A destructive action (role: .destructive) carries the card on out of the row at the speed you let go, so removing the row in the handler reads as one motion. The edge bubble stays put and can't be tapped again while the card is out. If the row is still there 0.35s after the card is out (the handler asked first, or deletes later), the card comes back home and the bar melts into its edge. That pause outlasts a List delete or a default withAnimation removal; a removal slower than that shows the card returning as the row fades. Any other action brings the card home the same way. The first declared action sits at the screen edge, matching .swipeActions.
  • Pass the same open: binding to every row in a list (with a unique id: per row) and only one row can be open at a time. Set the binding to nil to close all rows, or to a row's id to reveal its trailing actions (leading when there are none).
  • Swiping toward an edge with no actions gives with rubber-band resistance, never more than 60pt, and springs back.
  • background: sets the card's glass: nil leaves it neutral, a color tints it. .clear suits a list that draws its own surface: there is no card, the content slides on its own, and with nothing to bud from the bubbles wait in their slots and are uncovered as the content slides off them.
  • Style (SwipeActionRow.Style, also SwipeActionRowStyle): tileInk, cornerRadius, tileWidth, tileGap. surface is kept so existing code compiles but no longer draws anything: the card is glass. Set cornerRadius and tileGap to 0 for classic full-bleed list rows.
  • Reduce Motion keeps every state change and the arm haptic, but lands the card quickly with no overshoot or give, lets the bubbles wait in their slots and fade in with the reveal instead of budding, skips the arm bounce, and shades a pressed bubble instead of sinking it. All actions are exposed as VoiceOver custom actions on the row.
  • Need grouped activity with categorize, split and expanding detail? That is the Transaction Row screen in SwiftPieces Pro.

Usage

SwipeActionRowExample().preferredColorScheme(.light)

Parameters

ParameterDescription
idIdentity used with open. Defaults to a private id, which still lets a parent close the row.
leadingActions revealed by swiping right. The first one sits at the edge and fires on a full swipe.
trailingActions revealed by swiping left. The first one sits at the edge and fires on a full swipe.
backgroundThe card's glass. nil leaves it neutral glass and a color tints it. .clear suits a list that draws its own surface: the content slides with no card behind it, and the bubbles only show in the gap the row opens.
openShared binding to the id of the open row. Swiping a row stores its id here and closes every other row bound to it; set it to nil to close all, or to a row id to reveal that row's trailing actions.
styleCorner radius, bubble ink, bubble width and gap. Defaults to the house palette.
contentRow content.

Install

Pick one. Run it from the folder that contains your .xcodeproj and the files land inside your app.

Terminal

$npx swiftpieces add SwipeActionRow

Or ask your coding agent · Claude Code, Cursor or Xcode, once the MCP server is connected

>Add the SwiftPieces "Swipe Action Row" piece to my app

Or copy the source above into your app.

New to SwiftUI?If you know React, CSS or Tailwind, SwiftUI is easier to pick up than it looks.Try real app patterns first

Building a whole app? See SwiftPieces Pro →

All lists →

Build it yourself: SwiftUI loading states guide · SwiftUI cards guide

On this page

SwiftPiecesPro

Build the whole app with one library.

Production-ready screens, whole flows, complete app templates, a Build Kit your agent follows and Pro remixing.

54 screens · 46 patterns · 48 flows · 12 templates · 31 Build Kit skills

Explore Pro