Skip to content
Segmented Control preview
Rendered from the SwiftUI source on this page.

Segmented Control

From syxUI — written for both platforms, not translated between them.

A three-way selector with a thumb that slides between segments.

Navigation · SwiftUI · Flutter · iOS 17 · Flutter 3.27

  • navigation
  • segmented
  • picker
  • toggle
  • tabs
  • filter

The actual source

SegmentedControl.swift
// Segmented Control · syxUI · https://syxui.dev/components/segmented-control
// Free in any project. Keep this line and credit syxUI where a person can read it.

import SwiftUI

/// A sliding segmented control.
///
/// The white thumb is one view moved with `matchedGeometryEffect`, so it
/// travels between segments instead of cross-fading.
struct SegmentedControl: View {
    var options: [String] = ["Day", "Week", "Month"]
    var selection: String = "Week"
    var onSelect: (String) -> Void = { _ in }

    @State private var current: String = ""
    @Namespace private var namespace

    private var active: String { current.isEmpty ? selection : current }

    var body: some View {
        HStack(spacing: 0) {
            ForEach(options, id: \.self) { option in
                let isActive = option == active

                Button {
                    current = option
                    onSelect(option)
                } label: {
                    Text(option)
                        .font(.system(size: 14, weight: .semibold))
                        .foregroundStyle(isActive ? .black : Color(white: 0.42))
                        .frame(maxWidth: .infinity)
                        .frame(height: 34)
                        .background {
                            if isActive {
                                RoundedRectangle(cornerRadius: 9, style: .continuous)
                                    .fill(.white)
                                    .shadow(color: .black.opacity(0.10), radius: 3, y: 1)
                                    .matchedGeometryEffect(id: "thumb", in: namespace)
                            }
                        }
                        .contentShape(Rectangle())
                }
                .buttonStyle(.plain)
                .accessibilityAddTraits(isActive ? [.isSelected, .isButton] : .isButton)
            }
        }
        .padding(3)
        .background(Color(white: 0.93),
                    in: RoundedRectangle(cornerRadius: 12, style: .continuous))
        .animation(.spring(response: 0.3, dampingFraction: 0.82), value: active)
    }
}

#Preview {
    SegmentedControl()
        .frame(width: 280)
        .padding(30)
}
iOS 17 · No dependencies

SwiftUI note. Use the system Picker with .segmented when you want stock behaviour. Reach for this when you need the thumb, spacing, or type to match a custom design.

Dependencies

SwiftUI
No external dependencies

Requires iOS 17

Flutter
No external dependencies

Requires Flutter 3.27