Skip to content

Safe Areas ​

Handle device-specific safe areas for notches, rounded corners, and gesture navigation bars.

What Are Safe Areas? ​

Modern mobile devices have:

  • Notches - Camera/sensor cutouts at the top
  • Rounded corners - Content might be clipped
  • Gesture bars - Bottom home indicator areas

Safe areas ensure your content isn't hidden behind these elements.

Viewport Configuration ​

The template includes proper viewport configuration in layout.tsx:

html
<meta
  name="viewport"
  content="width=device-width, initial-scale=1, viewport-fit=cover"
/>

The viewport-fit=cover is required for safe area support.

CSS Environment Variables ​

Use CSS env() for safe area insets:

css
.header {
  padding-top: env(safe-area-inset-top, 0px);
}

.bottom-nav {
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.content {
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

The fallback value (e.g., 0px) is used on devices without notches.

useSafeArea Hook ​

Get safe area values in JavaScript:

tsx
import { useSafeArea } from '@/hooks/useSafeArea';

function MyComponent() {
  const { top, bottom, left, right } = useSafeArea();

  return (
    <div style={{ paddingTop: top, paddingBottom: bottom }}>
      Content respects safe areas
    </div>
  );
}

The hook:

  • Returns pixel values for each inset
  • Updates on resize and orientation change
  • Returns 0 for devices without safe areas

useStandalone Hook ​

Detect if running as installed PWA:

tsx
import { useStandalone } from '@/hooks/useSafeArea';

function MyComponent() {
  const isStandalone = useStandalone();

  // Show different UI when installed as PWA
  if (isStandalone) {
    return <FullscreenLayout />;
  }

  return <BrowserLayout />;
}

Common Patterns ​

css
.app-container {
  display: flex;
  flex-direction: column;
  height: 100dvh; /* Dynamic viewport height */
}

.header {
  flex-shrink: 0;
  padding-top: env(safe-area-inset-top);
}

.content {
  flex: 1;
  overflow-y: auto;
}

.bottom-nav {
  flex-shrink: 0;
  padding-bottom: env(safe-area-inset-bottom);
}

Bottom Sheet / Modal ​

css
.bottom-sheet {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding-bottom: env(safe-area-inset-bottom);
  border-radius: 24px 24px 0 0;
}

Testing ​

Chrome DevTools ​

  1. Open DevTools (F12)
  2. Toggle device toolbar
  3. Select a device with notch (iPhone 14)
  4. Verify content respects safe areas

Real Device ​

  1. Deploy to HTTPS
  2. Test on iOS and Android devices
  3. Check landscape orientation
  4. Test with gesture navigation enabled

Best Practices ​

  1. Always provide fallbacks - env(safe-area-inset-bottom, 0px)
  2. Use 100dvh - Dynamic viewport height respects mobile browser UI
  3. Test both orientations - Safe areas change in landscape
  4. Don't hardcode values - Different devices have different insets

Released under the MIT License.