Pattern · Settings

New

Notification Settings SwiftUI Block

The Notifications page of Settings: the real iOS permission, Push, Email and SMS per category, quiet hours and a digest that autosave.

Where people choose what reaches them and how. A status card reads the app's real permission and offers Turn on notifications or Open Settings, each category toggles its Push, Email and SMS chips, and quiet hours and the email digest sit beside them. Every change writes through your binding and saves after a short pause, with Saving, Saved and Not saved with Retry shown beside the group you changed.

  • SwiftUI
  • iOS 17.0+
  • notification-settings
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • Reads the real notification permission and asks or opens Settings from it
  • Push, Email and SMS chips for each kind of notification
  • Quiet hours with From and To times, and an Off, Daily or Weekly digest
  • Autosaves after a pause, with Saving, Saved and Retry beside each group
  • Loading, never asked, declined and quiet delivery states

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

A status card at the top reads the app's authorization from UNUserNotificationCenter and reads it again whenever the app comes back to the foreground. Allowed shows an "Allowed" chip and a "Banners, sounds and badges" row that opens the app's notification page in iOS Settings. Never asked shows "Notifications are off" with Turn on notifications, which asks iOS and shows a spinner until the person answers. Declined shows "Turned off in Settings" with Open Settings, and provisional delivery shows "Delivered quietly" with the same Turn on button. Under it, the Categories card lists each kind of notification with its symbol, title and a line on what it covers, and a chip for each channel it offers: Push, Email and SMS turn on and off with a tap and show a checkmark when on. Push chips dim while iOS has notifications off. Quiet hours is a switch that reveals From and To time rows. Email digest is a segmented Off, Daily or Weekly control with a line on what each sends. Every change writes through your binding at once; after a short pause the block runs your onSave and the card you changed shows "Saving…", then "Saved" beside its title. A thrown error shows "Not saved" with Retry beside the title and the message under the card. Pass nil while the preferences load and the block shows grey shapes in its own layout.

Notes

  • NotificationSettings(preferences:authorization:onSave:) takes a Binding<NotificationSettings.Preferences?> and an async throws save closure. It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column, such as a ScrollView with .padding(.horizontal, 20).
  • Preferences holds the categories, the quietHours and the digest. Preferences.sample is Messages (Push and Email on), Reminders (Push on) and Product news (Push and Email offered, both off), quiet hours off and a weekly digest.
  • A Category has a stable id for saving, a title, an optional detail line and SF Symbol, the available channels in display order (all three by default) and the channels that are on. Offer only the channels your backend can send.
  • Channel is .push, .email or .sms. QuietHours is isOn with from and to as Time (hour and minute in the person's calendar), 22:00 to 7:00 by default. Digest is .off, .daily or .weekly.
  • onSave receives the whole Preferences about 0.6 seconds after the last change, so a run of taps sends one request. A new change cancels a save that hasn't started. Throw to fail: the block shows a LocalizedError's errorDescription, or "Your changes weren't saved. Check your connection and try again." Retry sends the current preferences again. The binding keeps the person's choices either way.
  • authorization overrides what the card shows (.allowed, .quiet, .denied, .notDetermined), for previews or an app that tracks permission itself. Leave it nil and the block reads the system.
  • Turn on notifications calls requestAuthorization(options: [.alert, .sound, .badge]). Register for remote notifications in your own app delegate as usual; the block only reads and requests authorization. Open Settings and the Allowed row use UIApplication.openNotificationSettingsURLString.
  • Haptics: a selection tick on each chip, switch and digest change, success when a save lands and an error when one fails.
  • VoiceOver reads each category with the channels that are on ("Messages, Push and Email"), each chip as a toggle with On or Off, the digest as a selected tab, and announces "Saved", a failed save's message and the answer to the permission request. Every target is at least 44 points tall. At accessibility sizes the chips move under the title and stack when they no longer fit in a row.
  • Reduce Motion turns the chips, the quiet hours rows and the save status into short fades.
  • NotificationSettingsExample at the end of NotificationSettings.swift is the Notifications page from the preview: the sample preferences in a scroll view with a save that takes a moment and succeeds. It reads the system authorization, so a first run offers Turn on notifications. Pass wrapsInNavigationStack: false to push it in your own stack. The States preview shows the never-asked card with a save that fails, the declined card and the loading layout.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • Cards are color.surface with radius.lg; rows are 16 points in from the edge (space.lg) with SPHairline dividers in separator, inset to the text. Groups sit 24 points apart (space.xl) under type.headline titles in textPrimary.
  • Titles are type.body in textPrimary, detail lines type.footnote in textSecondary, symbols textSecondary, the Allowed row's arrow textTertiary. The save status is type.footnote: "Saving…" in textTertiary, "Saved" with a checkmark in textSecondary, "Not saved" and the error in danger, Retry semibold in textPrimary.
  • Channel chips are capsules in type.subhead: on is textPrimary with a checkmark on fill inside a faint textPrimary hairline, off is textSecondary inside a separator hairline. They are 32 points tall inside a 44 point target. The digest control is a fill track with a surfaceElevated thumb.
  • The Allowed chip is success on a tint of it. Turn on notifications and Open Settings are accent with accentOn text in type.headline, radius.md, the block's primary action. The quiet hours switch is accent with an accentOn thumb when on and fill with a white thumb when off.
  • Changes move with motion.snappy and the loaded layout fades in with motion.smooth; both become short fades under Reduce Motion.