이 글에서 정리하는 내용
이 글에서는 expo-status-bar가 무엇을 제어하는지부터 시작해서, 루트 레이아웃에 기본값을 두는 방법, 화면별로 상태바 스타일을 바꾸는 방법와 왜 분리해서 이해해야 하는지까지 한 번에 정리합니다. 읽고 나면 상태바 스타일과 상단 여백 문제를 같은 문제로 섞어 처리하는 실수를 줄일 수 있습니다.
expo-status-bar가 하는 일

이 글에서 먼저 분리해서 보려는 것은 상태바의 역할과 화면 레이아웃의 역할입니다. expo-status-bar는 시간, 배터리, 네트워크 아이콘이 보이는 상단 시스템 영역의 텍스트 색상, 숨김 여부, 애니메이션 같은 표시 상태를 제어할 때 사용하는 도구입니다. 즉 상단에 무엇이 보일지를 제어하는 쪽에 가깝고, 콘텐츠를 얼마나 아래로 밀어야 하는지는 별도 문제입니다.
제가 실무에서 가장 자주 본 혼동은 상태바와 를 하나로 보는 경우였습니다. 상태바가 밝게 보여야 해서 StatusBar를 만졌는데, 정작 버튼이 노치 아래에 깔리는 문제는 그대로 남아 있는 식입니다. 반대로 상단 padding만 늘렸는데 아이콘 색상은 여전히 배경과 겹쳐 안 보이는 경우도 많습니다. 그래서 expo-status-bar는 표시 스타일는 안전한 배치라고 먼저 나눠 이해하는 편이 훨씬 덜 헷갈립니다.
React Native StatusBar와의 관계
// expo-status-bar는 Expo 환경에 맞춘 기본값을 가진 StatusBar 컴포넌트를 사용합니다.
import { StatusBar } from 'expo-status-bar'; export default function App() { return <StatusBar style="auto" />;
}
expo-status-bar는 React Native StatusBar와 거의 같은 인터페이스를 사용하지만, Expo 프로젝트에서 바로 쓰기 좋게 정리된 패키지입니다. 그래서 Expo에서는 기본적으로 이 패키지부터 익히는 편이 자연스럽습니다. 이 패키지는 컴포넌트 방식과 imperative API를 모두 제공하지만, 일반적인 화면 구성에서는 컴포넌트 방식이 흐름을 읽기 더 쉽습니다.
가장 많이 쓰는 기본 사용법
가장 먼저 익혀둘 것은 루트 레이아웃에 기본 상태바 스타일을 두는 방식입니다. 앱 전체에 공통으로 적용할 기본값을 하나 두고, 특별한 화면에서만 덮어쓰는 구조가 관리하기 좋습니다. Expo Router를 쓴다면 보통 app/_layout.tsx에서 시작하는 편이 깔끔합니다.
루트 레이아웃에 기본값 두기
// 앱 전체 기본 상태바 스타일을 루트에 둡니다.
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar'; export default function RootLayout() { return ( <> <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> </Stack> <StatusBar style="dark" /> </> );
}
여기서 가장 자주 쓰는 prop은 style, hidden, animated입니다. style은 상태바 텍스트와 아이콘을 밝게 혹은 어둡게 보이게 하는 역할이고, hidden은 상태바 자체를 숨길지 결정합니다. animated는 스타일 변화나 숨김 전환이 바뀔 때 화면이 덜 튀게 해줍니다. 처음에는 prop을 많이 외우기보다 이 세 개만 정확히 익혀도 대부분의 화면은 대응할 수 있습니다.
추가로 Android에서는 backgroundColor나 translucent 같은 속성이 떠오르기 쉽지만, 최근 edge-to-edge 레이아웃 기준에서는 이 값이 항상 기대한 대로 동작하지 않을 수 있습니다. 특히 Android 15 이상에서는 상태바 배경색과 translucent 설정이 더 이상 효과가 없거나 폐기 대상으로 안내되고 있어서, expo-status-bar를 사용할 때도 이 부분을 예전 방식 그대로 믿으면 화면이 다르게 보일 수 있습니다. 그래서 요즘은 상단 배경을 화면 쪽에서 설계하고이 도구는 스타일과 가시성 중심으로 다루는 감각이 더 중요합니다.
필요할 때만 imperative API 쓰기
// expo-status-bar는 정적 메서드도 제공합니다.
// 다만 일반 화면에서는 컴포넌트 방식이 더 읽기 쉽습니다.
import { StatusBar } from 'expo-status-bar'; function openFullscreen() { StatusBar.setStatusBarHidden(true, 'fade');
} function closeFullscreen() { StatusBar.setStatusBarHidden(false, 'fade');
}
expo-status-bar는 setStatusBarStyle, setStatusBarHidden 같은 정적 메서드도 제공합니다. 영상 전체화면 전환처럼 이벤트 한 번에 맞춰 바로 상태를 바꾸고 싶을 때는 이런 방식이 편할 수 있습니다. 다만 화면 렌더링 흐름 안에서 스타일을 관리하는 일반 화면이라면 이 컴포넌트 방식이 더 예측 가능하고, 유지보수할 때도 읽기 쉽습니다.
그리고 style의 기본값이 auto라는 점도 알아두면 좋습니다. expo-status-bar에서 auto는 현재 색상 테마에 맞춰 light 또는 를 자동으로 고르는 값입니다. 즉 다크 모드와 라이트 모드를 모두 고려한 기본값이 필요할 때 이 auto 값은 꽤 실용적입니다.
| 자주 쓰는 prop | 핵심 역할 |
|---|---|
| style, hidden, animated | 텍스트 색상, 표시 여부, 전환 애니메이션 |
| backgroundColor, translucent | Android 관련 속성이지만 최신 환경에서는 제약을 함께 봐야 함 |
화면별 상태바 제어 방법
// 기본값은 루트에 두고, 특정 화면에서만 상태바 스타일을 덮어씁니다.
import { View, Text } from 'react-native';
import { StatusBar } from 'expo-status-bar'; export default function DetailScreen() { return ( <View style={{ flex: 1, backgroundColor: '#111827' }}> <StatusBar style="light" animated /> <Text style={{ color: '#fff' }}>상세 화면</Text> </View> );
}
상세 화면처럼 배경이 어두운 화면에서는 루트의 스타일을 그대로 쓰면 아이콘이 묻혀 보일 수 있습니다. 이럴 때는 그 화면 안에 StatusBar를 한 번 더 두고 style을 light로 덮어쓰면 됩니다. 저는 이 패턴을 목록 화면과 상세 화면의 분위기가 확실히 다를 때 자주 사용합니다.
여기서 기억할 점은 StatusBar를 여러 개 마운트할 수 있다는 점입니다. 전역 하나, 특정 화면 하나가 동시에 존재해도 이상한 구조는 아닙니다. 다만 컴포넌트 기반 설정과 정적 메서드 기반 설정을 한 prop에 섞어서 쓰면 다음 렌더 때 값이 덮이면서 흐름을 추적하기 어려워질 수 있으니, 한 화면 안에서는 되도록 컴포넌트 방식으로 통일하는 편이 안정적입니다.
전역 기본값과 화면 전용 값을 같이 쓰는 기준
// 밝은 배경 화면은 루트 기본값을 그대로 쓰고,
// 어두운 배경 화면만 개별 StatusBar를 추가합니다.
function ListScreen() { return <View style={{ flex: 1, backgroundColor: '#ffffff' }} />;
} function PhotoScreen() { return ( <View style={{ flex: 1, backgroundColor: '#000000' }}> <StatusBar style="light" /> </View> );
}
기준은 단순합니다. 앱 전체에서 대부분 같은 톤이라면 루트에 하나만 두고 끝내면 됩니다. 반대로 특정 화면만 배경색이나 몰입감이 크게 다르다면 그 화면 안에서만 따로 선언하면 됩니다. 모든 화면마다 StatusBar를 습관처럼 넣기보다, 기본값에서 벗어나는 화면에만 추가하는 편이 구조를 읽기 쉽습니다.
와 플랫폼 차이

상태바가 예쁘게 보이는 것과 콘텐츠가 안전하게 배치되는 것은 다른 문제입니다. 는 노치, 상태바, 홈 인디케이터 같은 시스템 영역을 피해 콘텐츠를 배치하기 위한 개념입니다. 그래서 상단 아이콘 색을 바꾸려면 StatusBar를 보고, 헤더나 버튼이 가려지지 않게 하려면 SafeAreaView나 useSafeAreaInsets를 봐야 합니다.
상단 배경은 StatusBar로, 여백은 로 분리하기
// 상태바 스타일과 안전 영역 여백을 각자 맡겨서 처리합니다.
import { View, Text } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; export default function ProfileScreen() { const insets = useSafeAreaInsets(); return ( <SafeAreaView style={{ flex: 1, backgroundColor: '#f9fafb' }}> <StatusBar style="dark" /> <View style={{ paddingTop: 12, paddingHorizontal: 20, paddingBottom: insets.bottom + 16 }}> <Text>프로필 화면</Text> </View> </SafeAreaView> );
}
이런 식으로 분리하면 책임이 선명해집니다. StatusBar는 상단 시스템 텍스트가 밝을지 어두울지 정하고, SafeAreaView는 화면 바깥쪽 위험 구간을 피하게 해줍니다. 하단 고정 버튼처럼 섬세한 보정이 필요할 때는 useSafeAreaInsets로 값을 직접 더하는 편이 더 유연합니다.
특히 Android에서는 edge-to-edge 기준이 강해지면서, 예전처럼 반투명 상태바만 켜 두고 여백 문제를 대충 넘기기 어려워졌습니다. 게다가 React Native 기본 SafeAreaView는 현재 deprecated로 안내되고 있어서, Expo에서는 react-native-safe-area-context 기준으로 정리하는 편이 더 안전합니다. 그래서 요즘은 Android와 iOS를 따로 외우기보다, 먼저 safe area로 겹침을 막고 그 위에서 status bar style만 조정하는 순서로 생각하면 실수가 줄어듭니다.
결론
expo-status-bar를 볼 때 가장 먼저 잡아둘 기준은 이것입니다. 이 도구는 상단 시스템 바의 보이는 상태를 제어하는 용도이고, 콘텐츠 배치 문제를 직접 해결하는 도구는 아닙니다. 앱 전체 기본값은 루트에 두고, 분위기가 다른 화면만 개별로 덮어쓰며, 겹침 문제는 로 분리해서 처리하면 구조가 훨씬 단정해집니다. 이 흐름만 익혀도 상태바 때문에 화면이 어색해 보이거나 상단 여백이 꼬이는 문제를 훨씬 안정적으로 다룰 수 있습니다.
많이 받는 질문
Q. expo-status-bar와 react-native의 StatusBar 중 무엇부터 쓰는 편이 좋나요?
Expo 프로젝트라면 보통 expo-status-bar부터 보는 편이 자연스럽습니다. 인터페이스가 익숙하고 Expo 환경에 맞춘 기본값을 바로 활용할 수 있기 때문입니다.
Q. 상태바를 바꿨는데도 상단 콘텐츠가 노치와 겹칩니다. 왜 그런가요?
상태바 스타일 제어와 안전 영역 보정은 다른 문제이기 때문입니다. 이 경우는 StatusBar보다 SafeAreaView나 useSafeAreaInsets가 필요한 상황입니다.
Q. 모든 화면에 StatusBar를 각각 넣어야 하나요?
그럴 필요는 없습니다. 대부분의 화면이 같은 톤이라면 루트에 기본값 하나만 두고, 특정 화면만 예외적으로 다른 스타일이 필요할 때만 화면 안에 추가하는 편이 관리하기 쉽습니다.
같이 읽으면 좋은 글
- Expo Safe Area 사용법: 화면 여백을 안전하게 잡는 방법
- Expo Router 사용법: app 폴더와 Stack Tabs 구조 잡기
- Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리
“Expo Status Bar 사용법: Safe Area와 화면별 설정”에 대한 1개의 생각