UITableViewCell
iOS Development
Custom Swipe Actions
Objective-C
Swift

Custom edit view in UITableViewCell while swipe left. Objective-C or Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

On iOS, the standard way to show actions when a user swipes left on a UITableViewCell is to provide trailing swipe actions through the table view delegate. UIKit supports custom action titles, colors, and images, but it does not let you drop in a fully arbitrary edit view through the built-in API. If you need a truly custom panel, you usually have to build your own swipe interaction.

Use the Built-In Swipe Action API First

For iOS 11 and later, the recommended API is UIContextualAction with UISwipeActionsConfiguration. This covers most real app needs such as Edit, Delete, Archive, or Flag.

Swift example:

swift
1import UIKit
2
3class TasksViewController: UITableViewController {
4    var items = ["Buy milk", "Ship release", "Reply to client"]
5
6    override func tableView(
7        _ tableView: UITableView,
8        trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
9    ) -> UISwipeActionsConfiguration? {
10        let edit = UIContextualAction(style: .normal, title: "Edit") { _, _, completion in
11            self.presentEditor(for: indexPath)
12            completion(true)
13        }
14        edit.backgroundColor = .systemBlue
15        edit.image = UIImage(systemName: "pencil")
16
17        let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, completion in
18            self.items.remove(at: indexPath.row)
19            tableView.deleteRows(at: [indexPath], with: .automatic)
20            completion(true)
21        }
22
23        let config = UISwipeActionsConfiguration(actions: [delete, edit])
24        config.performsFirstActionWithFullSwipe = false
25        return config
26    }
27
28    private func presentEditor(for indexPath: IndexPath) {
29        print("Edit \(items[indexPath.row])")
30    }
31}

That gives you a polished native interaction with minimal code and correct table-view behavior.

Objective-C Version

The same pattern works in Objective-C:

objective-c
1- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView
2trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
3    UIContextualAction *editAction =
4        [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
5                                                title:@"Edit"
6                                              handler:^(
7                                                  UIContextualAction *action,
8                                                  __kindof UIView *sourceView,
9                                                  void (^completionHandler)(BOOL)) {
10            [self handleEditAtIndexPath:indexPath];
11            completionHandler(YES);
12        }];
13
14    editAction.backgroundColor = [UIColor systemBlueColor];
15    editAction.image = [UIImage systemImageNamed:@"pencil"];
16
17    UIContextualAction *deleteAction =
18        [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
19                                                title:@"Delete"
20                                              handler:^(
21                                                  UIContextualAction *action,
22                                                  __kindof UIView *sourceView,
23                                                  void (^completionHandler)(BOOL)) {
24            completionHandler(YES);
25        }];
26
27    UISwipeActionsConfiguration *config =
28        [UISwipeActionsConfiguration configurationWithActions:@[deleteAction, editAction]];
29    config.performsFirstActionWithFullSwipe = NO;
30    return config;
31}

If your goal is a branded action area with icons and custom colors, this is usually enough.

When “Custom Edit View” Means a Real Custom Panel

Many developers actually want more than action buttons. They want a fully custom view with labels, toggles, or a mini form that appears as the cell is swiped. The built-in swipe API is not designed for that.

If you need that level of control, the usual approach is:

  1. create a custom cell subclass
  2. place the main content view above a hidden action container
  3. add a pan gesture or use scroll mechanics
  4. animate the content view horizontally to reveal the custom container

A simplified Swift sketch:

swift
1class SwipeCell: UITableViewCell {
2    private let actionsView = UIView()
3    private let foregroundView = UIView()
4
5    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
6        super.init(style: style, reuseIdentifier: reuseIdentifier)
7
8        actionsView.backgroundColor = .systemGray5
9        contentView.addSubview(actionsView)
10        contentView.addSubview(foregroundView)
11    }
12
13    required init?(coder: NSCoder) {
14        fatalError("init(coder:) has not been implemented")
15    }
16
17    func setRevealed(_ revealed: Bool, animated: Bool) {
18        let targetX: CGFloat = revealed ? -120 : 0
19        let changes = {
20            self.foregroundView.transform = CGAffineTransform(translationX: targetX, y: 0)
21        }
22
23        if animated {
24            UIView.animate(withDuration: 0.2, animations: changes)
25        } else {
26            changes()
27        }
28    }
29}

This gives you freedom, but it also means you now own gesture conflicts, reuse behavior, accessibility, and closing previously opened cells.

Choosing the Right Approach

Use built-in swipe actions when:

  • you need standard actions such as edit or delete
  • buttons with text, color, and image are enough
  • you want native behavior and less maintenance

Build a custom swipeable view only when:

  • the built-in action buttons cannot express the UI
  • you are prepared to manage gesture and reuse complexity
  • the interaction is central enough to justify custom code

Common Pitfalls

The biggest pitfall is trying to force UISwipeActionsConfiguration to host arbitrary subviews. It is meant for action buttons, not for embedding a free-form edit panel.

Another common problem is state leakage during cell reuse. If one cell is half-swiped and reused for another row, the UI can appear broken unless you reset state in prepareForReuse.

Gesture conflicts are also easy to create. Custom pan handling can interfere with table scrolling, reorder gestures, or system edge swipes if it is not carefully implemented.

Finally, remember accessibility. A flashy swipe interaction is not enough if VoiceOver users cannot discover or trigger the same actions through accessible controls.

Summary

  • For most apps, use UIContextualAction and UISwipeActionsConfiguration.
  • UIKit supports custom button-style swipe actions, not arbitrary embedded edit views.
  • If you need a real custom panel, build a custom cell and manage the swipe behavior yourself.
  • Custom swipe UIs require careful handling of reuse, gestures, and accessibility.
  • Start with the native API and only go custom when the built-in model is clearly insufficient.

Course illustration
Course illustration

All Rights Reserved.