Skip to content

matteozappia/SlideMenu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SlideMenu Icon

SlideMenu

A lightweight, gesture-driven side menu for SwiftUI. Fully customizable, zero dependencies.

Swift 6.0+ iOS 15+

Overview

  • Slides from the left or right edge
  • Horizontal drag gesture with axis locking, works alongside ScrollView, List, and Form
  • Configurable edge detection zone to avoid conflicts with interactive content
  • Tap-to-dismiss overlay with customizable color and opacity
  • Matches device display corner radius for a native feel
  • All appearance settings exposed as SwiftUI environment modifiers
  • SlideMenuButton reads the toggle action from the environment, no bindings needed

Installation

dependencies: [
    .package(url: "https://github.com/matteozappia/SlideMenu.git", branch: "main")
]
import SlideMenu

Usage

Basic

SlideMenu {
    Text("Main Content")
} menu: {
    VStack {
        Text("Home")
        Text("Settings")
    }
}

With a Toggle Button

Place a SlideMenuButton anywhere inside the main content. It picks up the toggle action from the environment automatically.

SlideMenu {
    NavigationStack {
        Text("Hello")
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    SlideMenuButton(systemImage: "sidebar.leading")
                }
            }
    }
} menu: {
    Text("Menu")
}

Custom label:

SlideMenuButton {
    Label("Menu", systemImage: "line.3.horizontal")
}

Direction

SlideMenu(direction: .right) {
    Text("Main")
} menu: {
    Text("Right Side Menu")
}

Edge Zone Width

Control how far from the screen edge a swipe is recognized. Defaults to 30 points. Increase if users have trouble opening the menu, decrease to reduce conflicts with horizontal controls.

SlideMenu(edgeZoneWidth: 50) {
    // ...
} menu: {
    // ...
}

Menu-Driven Navigation

Use the menu to switch views in the main content area. Instead of putting NavigationLinks in the menu (which would push inside the menu panel), use buttons that set a @State selection, and read slideMenuToggle from the environment to close the menu on tap.

slideMenuToggle is available in both the main and menu content.

enum Page: String, CaseIterable, Identifiable {
    case home, settings, about
    var id: Self { self }
}

struct MyApp: View {
    @State private var selection: Page = .home

    var body: some View {
        SlideMenu {
            NavigationStack {
                switch selection {
                case .home:     HomeView()
                case .settings: SettingsView()
                case .about:    AboutView()
                }
            }
        } menu: {
            MenuList(selection: $selection)
        }
    }
}

struct MenuList: View {
    @Binding var selection: Page
    @Environment(\.slideMenuToggle) private var toggle

    var body: some View {
        VStack(alignment: .leading, spacing: 24) {
            ForEach(Page.allCases) { page in
                Button(page.rawValue.capitalized) {
                    selection = page
                    toggle()
                }
            }
        }
        .padding(.leading, 24)
        .padding(.top, 80)
    }
}

This keeps the NavigationStack in the main area, so any NavigationLink inside destination views pushes correctly within the main content, not the menu.

Full Example

SlideMenu(direction: .left, edgeZoneWidth: 40) {
    NavigationStack {
        ContentView()
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    SlideMenuButton(systemImage: "sidebar.leading")
                }
            }
    }
} menu: {
    MenuView()
}
.slideMenuWidth(300)
.slideMenuBackground(.ultraThinMaterial)
.slideMenuOverlayOpacity(0.5)
.slideMenuBorderWidth(0)
.slideMenuAnimation(.bouncy(duration: 0.5, extraBounce: 0.15))

Customization

All appearance is configured through view modifiers. Apply them to the SlideMenu or any ancestor.

Menu Width

.slideMenuWidth(320)

Background

Accepts any ShapeStyle, solid colors, materials, gradients:

.slideMenuBackground(Color(.systemBackground))
.slideMenuBackground(.ultraThinMaterial)
.slideMenuBackground(LinearGradient(colors: [.blue, .purple], startPoint: .top, endPoint: .bottom))

Overlay

The dimming overlay drawn on the main content while the menu is open:

.slideMenuOverlayColor(.black)
.slideMenuOverlayOpacity(0.4)

Border

The subtle stroke around the main content while the menu is visible:

.slideMenuBorderColor(.gray)
.slideMenuBorderWidth(0.5)

Animation

.slideMenuAnimation(.spring(response: 0.35, dampingFraction: 0.85))
.slideMenuAnimation(.bouncy(duration: 0.5, extraBounce: 0.15))
.slideMenuAnimation(.easeInOut(duration: 0.3))

API Reference

Parameters

Parameter Type Default Description
direction SlideMenuDirection .left Edge the menu slides from
edgeZoneWidth CGFloat 30 Touch zone width along the screen edge

Modifiers

Modifier Type Default Description
.slideMenuWidth CGFloat 290 Menu panel width
.slideMenuBackground ShapeStyle .background Background for both panels
.slideMenuOverlayColor Color auto Dimming overlay color
.slideMenuOverlayOpacity CGFloat 0.6 Max overlay opacity
.slideMenuBorderColor Color .primary Border stroke color
.slideMenuBorderWidth CGFloat 1 Border stroke width
.slideMenuAnimation Animation .spring(...) Open/close animation

Demo App

The Demo/ folder contains a demo app showcasing all features. The demo app requires iOS 16+, but the SlideMenu framework itself supports iOS 15+.

Contributing

Contributions welcome. Please feel free to submit a Pull Request.

License

MIT. See LICENSE for details.

About

A lightweight, modern, gesture-driven side menu component for SwiftUI with edge-swipe navigation, fully customizable, zero dependencies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages