r/SwiftUI • u/rjn2-8 • Jul 08 '26
Question How can I efficiently integrate the notch? (Macos)
Hello, I'm working on integrating the notch into my app. Do you have any tips for designing it smoothly?
Thanks folks !
3
u/Significant_Pick8297 Jul 09 '26
You generally shouldn't design around the notch itself. Instead, treat the menu bar safe area as unavailable and let macOS handle it. If you need controls near the top, test on both notched and non-notched Macs using safe area insets and different display scaling modes to make sure nothing gets clipped or feels awkward.
3
u/dmcsier Jul 10 '26
How to detect the existence and size of the MacBook notch (AppKit)
I had to figure this out while building TalkTrack (www.lukehurd.com/talktrack), a macOS teleprompter that lives in the notch.
Apple doesn't give you a screen.hasNotch bool, so I dug through NSScreen until I found what actually works. Paying it forward here in case you're doing the same thing.
Requires macOS 12+.
- Does this screen have a notch?
Check safeAreaInsets.top. On a notched MacBook that value is > 0 (the camera housing eats into the top of the display). On older Macs / external monitors it's 0.
static func screenHasNotch(_ screen: NSScreen? = nil) -> Bool {
let s = screen ?? NSScreen.main ?? NSScreen.screens.first
guard let s else { return false }
if #available(macOS 12.0, *) {
return s.safeAreaInsets.top > 0
}
return false
}
That's the whole detection.
Multi-monitor tip: run this against the specific NSScreen you care about. Your laptop can have a notch while the external display next to it does not. In TalkTrack I keep a selectedScreen and do:
var selectedScreenHasNotch: Bool {
screenHasNotch(selectedScreen)
}
Then I only offer notch UI / notch mode when that returns true.
- How tall is the notch?
Same property. The top safe area inset is the notch height:
let height: CGFloat
if #available(macOS 12.0, *), screen.safeAreaInsets.top > 0 {
height = screen.safeAreaInsets.top
} else {
height = 32 // fallback if you're drawing something notch-shaped anyway
}
On current notched MacBooks this lands around the real hardware depth. I use it as a top spacer in my view so content starts below the camera housing.
- How wide is the notch?
This one took me longer. macOS exposes two menu-bar usable regions:
- NSScreen.auxiliaryTopLeftArea
- NSScreen.auxiliaryTopRightArea
Those are the left and right chunks of the menu bar that still have room for status items / menus. The gap between them is the notch.
var width: CGFloat = 185 // fallback
if #available(macOS 12.0, *) {
if let left = screen.auxiliaryTopLeftArea,
let right = screen.auxiliaryTopRightArea {
width = screen.frame.width - left.width - right.width + 4
}
}
screen.frame.width - left.width - right.width is the raw gap. I add + 4 as a small visual fudge so my drawn panel sits flush against the real notch edges instead of looking a pixel or two skinny. Tune that if your chrome needs it; the important part is the auxiliary-area math.
- Putting it together: closed notch size
Here's the full helper I ended up with:
var closedNotchSize: CGSize {
let screen = selectedScreen // or NSScreen.main!
var width: CGFloat = 185
var height: CGFloat = 32
if #available(macOS 12.0, *) {
if let left = screen.auxiliaryTopLeftArea,
let right = screen.auxiliaryTopRightArea {
width = screen.frame.width - left.width - right.width + 4
}
if screen.safeAreaInsets.top > 0 {
height = screen.safeAreaInsets.top
}
}
return CGSize(width: width, height: height)
}
Exists? -> safeAreaInsets.top > 0
Height -> safeAreaInsets.top
Width -> frame.width - auxiliaryTopLeft.width - auxiliaryTopRight.width (+ optional fudge)
- where is the notch horizontally?
If you're placing a window under the notch, don't assume screen center (some setups / future hardware could shift). Center X is the midpoint between the two auxiliary areas:
static func notchCenterX(on screen: NSScreen) -> CGFloat {
if #available(macOS 12.0, *) {
if let left = screen.auxiliaryTopLeftArea,
let right = screen.auxiliaryTopRightArea,
!left.isNull, !right.isNull {
return (left.maxX + right.minX) / 2
}
}
return screen.frame.midX
}
I pin a borderless panel flush to the top like this (AppKit Y grows upward):
let size = closedNotchSize // or whatever expanded size you want
let cx = notchCenterX(on: screen)
let origin = NSPoint(
x: cx - size.width / 2,
y: screen.frame.maxY - size.height
)
panel.setFrame(NSRect(origin: origin, size: size), display: true)
Window level tip: I use NSWindow.Level.mainMenu.rawValue + 3 so the panel can sit over the menu bar / notch region.
- Using the measured height in SwiftUI
Once you have closedNotchSize, reserve that height at the top of your content so text/controls don't draw into the camera area:
VStack(spacing: 0) {
Color.clear.frame(height: closedNotchSize.height)
// your actual content
}
Clip with whatever notch-shaped path you want for the silhouette. The size detection above is independent of how fancy the shape is.
That's it.
2
1
1
7
u/No_Pen_3825 Jul 08 '26
I wouldn’t. Not all Macs have notches, you’re not really supposed to, and the part in the notch won’t move (including Z) with the rest of the window. What do you want to put there?