Bonsplit is a custom tab bar and layout split library for macOS apps. Out of the box 120fps animations, drag-and-drop reordering, SwiftUI support & keyboard navigation.

.package(url: "https://github.com/almonk/bonsplit.git", from: "1.0.0")

### Features

Simple, Powerful API

Create Tabs

Create tabs with optional icons and dirty indicators. Target specific panes or use the focused pane.

let tabId = controller.createTab(
title: "Document.swift",
icon: "swift",
isDirty: false,
inPane: paneId
)

Split Panes

Split any pane horizontally or vertically. New panes are empty by default, giving you full control.

// Split focused pane horizontally
let newPaneId = controller.splitPane(
orientation: .horizontal
)
// Split with a tab already in the new pane
controller.splitPane(
orientation: .vertical,
withTab: Tab(title: "New", icon: "doc")
)

Update Tab State

Update tab properties at any time. Changes animate smoothly.

// Mark document as modified
controller.updateTab(tabId, isDirty: true)
// Rename tab
controller.updateTab(tabId, title: "NewName.swift")
// Change icon
controller.updateTab(tabId, icon: "doc.text")

Navigate Focus

Programmatically navigate between panes using directional navigation.

// Move focus between panes
controller.navigateFocus(direction: .left)
controller.navigateFocus(direction: .right)
controller.navigateFocus(direction: .up)
controller.navigateFocus(direction: .down)
// Or focus a specific pane
controller.focusPane(paneId)

### Reference

Reference

Complete reference for all Bonsplit classes, methods, and configuration options.

BonsplitController

The main controller for managing tabs and panes. Create an instance and pass it to BonsplitView.

Tab Operations
Split Operations
Focus Management
Query Methods

BonsplitDelegate

Implement this protocol to receive callbacks about tab bar events. All methods have default implementations and are optional.

Tab Callbacks
Pane Callbacks

BonsplitConfiguration

Configure behavior and appearance. Pass to BonsplitController on initialization.

allowSplits
Bool

Enable split buttons and drag-to-split

Default: true

allowCloseTabs
Bool

Show close buttons on tabs

Default: true

allowCloseLastPane
Bool

Allow closing the last remaining pane

Default: false

allowTabReordering
Bool

Enable drag-to-reorder tabs within a pane

Default: true

allowCrossPaneTabMove
Bool

Enable moving tabs between panes via drag

Default: true

autoCloseEmptyPanes
Bool

Automatically close panes when their last tab is closed

Default: true

contentViewLifecycle
ContentViewLifecycle

How tab content views are managed when switching tabs

Default: .recreateOnSwitch

Example
let config = BonsplitConfiguration(
allowSplits: true,
allowCloseTabs: true,
allowCloseLastPane: false,
autoCloseEmptyPanes: true,
contentViewLifecycle: .keepAllAlive
)
let controller = BonsplitController(configuration: config)
Content View Lifecycle

Controls how tab content views are managed when switching between tabs.

ModeMemoryStateUse Case
.recreateOnSwitchLowNoneSimple content
.keepAllAliveHigherFullComplex views, forms
Appearance
tabBarHeight
CGFloat

Height of the tab bar

Default: 33

tabMinWidth
CGFloat

Minimum width of a tab

Default: 140

tabMaxWidth
CGFloat

Maximum width of a tab

Default: 220

tabSpacing
CGFloat

Spacing between tabs

Default: 0

minimumPaneWidth
CGFloat

Minimum width of a pane

Default: 100

minimumPaneHeight
CGFloat

Minimum height of a pane

Default: 100

showSplitButtons
Bool

Show split buttons in the tab bar

Default: true

animationDuration
Double

Duration of animations in seconds

Default: 0.15

enableAnimations
Bool

Enable or disable all animations

Default: true

Presets
.default
BonsplitConfiguration

Default configuration with all features enabled

.singlePane
BonsplitConfiguration

Single pane mode with splits disabled

.readOnly
BonsplitConfiguration

Read-only mode with all modifications disabled