Yet another super simple spotlight instruction framework for UIKit iOS.

Why Yokoso?

  • Supports device rotation / iPad SplitView
  • Closure style callback (no complex datasources or delegates)
  • Checks if interested view is inside window’s bounds
  • Stateless ( manage by yourself )



How to use

It’s super simple. Import the module,

import Yokoso

initialize InstructionManager,

let manager = InstructionManager(overlayBackgroundColor: .overlayBackground)

then use InstructionManager‘s interface to show or close your Instruction.

/// - throws: `InstructionError.interestedViewOutOfBounds`
public func show(
    _ instruction: Instruction,
    in view: UIView,
    onFinish: @escaping (Bool) -> ()
) throws

Showing single Instruction

To simplify internal implementation, we don’t check view state internally, but just redrawing everything again. So make sure you know isShowingInstruction state to avoid calling show() multiple time. It’s safe to invoke show while showing, but it would trigger overlay’s fade animation again.

if isShowingInstruction { return }

isShowingInstruction = true

do {

    try instructionManager.show(
            message: .init(
                attributedString: attributedString,
                backgroundColor: uicolor
            nextButton: .simple("Next"),
            sourceView: label
        in: view
    ) { [weak self] success in
        guard let me = self else { return }

        // called when instruction "did" finish

        me.isShowingInstruction = false

} catch {

    isShowingInstruction = false

    if let error = error as? InstructionError {

Showing multiple Instructions

Yokoso is stateless. If you want to show multiple instructions in order, then call show() in order. This way you have more control over the timings, comparing to passing multiple Instruction at once.

private func startI1() {
            message: .init(attributedString: makeMessage("Hi with simple Next button. Tap anywhere to continue."), backgroundColor: .background),
            nextButton: .simple("Next"),
            sourceView: label1
    ) { [weak self] success in

        self?.startI2() // NOTE: Starting next instruction.


private func startI2() {

Please refer to example app inside repository for further customization.


  • Swift Package Manager
  • CocoaPods
  • Carthage


Any contributions are warmly welcomed.?

  • Feature Request / Pull Request
  • Bug Report
  • Question!




View Github