Skip to content

liam-i/BlankSlate

Repository files navigation

BlankSlate

Swift Platforms CocoaPods SPM Carthage License

BlankSlate is a drop-in UIView extension for showing empty datasets whenever the view has no content to display.

ScreenShots

Requirements

  • iOS 13.0+
  • tvOS 13.0+
  • visionOS 1.0+
  • Xcode 15.0+
  • Swift 5.9+

Installation

Swift Package Manager

...using swift build

If you are using the Swift Package Manager, add a dependency to your Package.swift file and import the BlankSlate library into the desired targets:

dependencies: [
    .package(url: "https://github.com/liam-i/BlankSlate.git", from: "0.7.1")
],
targets: [
    .target(
        name: "MyTarget", dependencies: [
            .product(name: "BlankSlate", package: "BlankSlate")
        ])
]

...using Xcode

If you are using Xcode, then you should:

  • File > Add Package Dependencies...
  • Add https://github.com/liam-i/BlankSlate.git
  • Select "Up to Next Minor" with "0.7.1"

Tip

For detailed tutorials, see: Apple Docs

CocoaPods

If you're using CocoaPods, add this to your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
# Or use CDN source
# source 'https://cdn.cocoapods.org/'
platform :ios, '13.0'
use_frameworks!

target 'MyApp' do
  pod 'BlankSlate', '~> 0.7.1'
end

And run pod install.

Important

CocoaPods 1.13.0 or newer is required.

Carthage

If you're using Carthage, add this to your Cartfile:

github "liam-i/BlankSlate" ~> 0.7.1

And run carthage update --platform iOS --use-xcframeworks.

Usage

Basic Setup

Conform to BlankSlate.DataSource to provide empty state content, then assign it to your view:

import BlankSlate

class MyViewController: UITableViewController, BlankSlate.DataSource, BlankSlate.Delegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.bs.setDataSourceAndDelegate(self)
    }

    // MARK: - BlankSlate.DataSource

    func image(forBlankSlate view: UIView) -> UIImage? {
        UIImage(named: "empty_placeholder")
    }

    func title(forBlankSlate view: UIView) -> NSAttributedString? {
        NSAttributedString(string: "No Data", attributes: [
            .font: UIFont.systemFont(ofSize: 20, weight: .medium),
            .foregroundColor: UIColor.secondaryLabel
        ])
    }

    func buttonTitle(forBlankSlate view: UIView, for state: UIControl.State) -> NSAttributedString? {
        guard state == .normal else { return nil }
        return NSAttributedString(string: "Reload", attributes: [
            .font: UIFont.systemFont(ofSize: 16, weight: .semibold),
            .foregroundColor: UIColor.systemBlue
        ])
    }

    // MARK: - BlankSlate.Delegate

    func blankSlate(_ view: UIView, didTapButton sender: UIButton) {
        // Handle retry
        loadData()
    }
}

The empty dataset displays automatically by observing reloadData() calls — no manual reload needed for UITableView and UICollectionView.

Status-Driven (Zero Configuration)

For common loading/empty/error patterns, use the built-in StatusDrivenDataSource:

let statusDS = BlankSlate.StatusDrivenDataSource(view: tableView)
statusDS.onRetry = { [weak self] in self?.loadData() }

// Trigger state changes:
tableView.bs.reload(with: .loading)   // Shows spinner
tableView.bs.reload(with: .success)   // Shows "No Data" if table is empty
tableView.bs.reload(with: .failure)   // Shows error + retry button

Plain UIView / UIScrollView

For non-table/collection views, call reload() manually:

let scrollView = UIScrollView()
scrollView.bs.dataSource = self
scrollView.bs.reload()           // Evaluate and show/hide blank slate
scrollView.bs.dismiss()          // Manually remove blank slate

SwiftUI

import BlankSlate

List(items) { item in
    ItemRow(item: item)
}
.blankSlate(isEmpty: items.isEmpty, title: "No Items", detail: "Pull to refresh")

Transition Animations

func transition(forBlankSlate view: UIView) -> BlankSlate.Transition {
    .fadeIn(duration: 0.3)    // or .slideUp, .slideDown, .scale, .bounce
}

Custom Layout & Alignment

func alignment(forBlankSlate view: UIView) -> BlankSlate.Alignment {
    .center(.offset(y: -50))  // 50pt above center
}

func layout(forBlankSlate view: UIView, for element: BlankSlate.Element) -> BlankSlate.Layout {
    .init(edgeInsets: UIEdgeInsets(top: 20, left: 16, bottom: 20, right: 16))
}

For the complete API reference, see the source documentation in Sources/DataSource.swift and Sources/Delegate.swift.

Example

To run the example project, first clone the repo, then cd to the root directory and run pod install. Then open BlankSlate.xcworkspace in Xcode.

Credits and thanks

License

BlankSlate is available under the MIT license. See the LICENSE file for more info.

About

A drop-in UIView extension for showing empty datasets whenever the view has no content to display.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors