topBar
The bar at the top of a screen in a stack: its title, buttons, back button, search and look.
Set it
In the definition of the screen, from the screen while it shows, or for every screen of the app. The screen's own options go over the app defaults, and the options set while it shows go over both, key by key. More: Screen options.
export const ProfileScreen = defineScreen({
component: Profile,
options: (s) =>
s
.title('Profile')
.largeTitle()
.topBar({ background: { color: '#F3E9D2' }, noBorder: true }),
});
Chain methods
Short ways to set the most common keys in an options chain.
| Method | Sets |
|---|---|
s.title(text | title) | topBar.title; a string is its text. |
s.subtitle(text | subtitle) | topBar.subtitle; a string is its text. |
s.largeTitle(on = true) | topBar.largeTitle; true shows it, an object sets it. |
s.hideTopBar(hidden = true) | topBar.visible: false hides the bar. |
s.topBar(options) | Any keys of topBar. |
Options
Every key, with the platforms it works on. A dashed platform means the key does nothing there.
54 options shown
Whether the bar shows. It applies on each appearance and on mergeOptions; the change is animated unless animate is false. A hidden bar puts the screen under it and shows no large title; on iOS the top safe area inset comes from visible: false only, not from a bar hidden by scrolling. On Android hiding slides the bar up and then removes it; on push and pop it moves with the transition, and showing resets the hideOnScroll offset.
Whether the change of visible is animated, also in mergeOptions. On Android false applies the visibility at once on push, pop and setStackRoot.
Whether the bar goes away when the content is scrolled down and comes back on scrolling up. The screen goes under the bar by itself, so the list must keep its first rows clear of it (iOS contentInsetAdjustmentBehavior="automatic", Android paddingTop of the top safe area inset). On iOS before 27 it is the stack's hide-on-swipe, and the swipe back keeps working; on iOS 27+ it is the system minimization of the bar on scroll down, and without the option the bar never minimizes. On Android it doesn't work under a large title or while a search is open. A change by mergeOptions applies at once.
Whether a tap on the screen that nothing handled hides the bar, and the next tap shows it. The value of the shown screen applies on each appearance, so a screen below keeps its own after coming back.
Whether the bar hides while the keyboard is up and returns when it closes, unless the screen hides the bar with visible: false.
The color of the left buttons that have no color of their own. Without it, the tint of the bar on iOS, the theme's text color on Android with icons untinted. The buttons get copies with the color, so a color doesn't stay in buttons shared with other screens. mergeOptions repaints the shown buttons and keeps the color in the screen's own buttons through the next appearance and a theme switch. On iOS it sets the text color and the tint; an SF Symbol without a color is drawn as a template, disableIconTint keeps its colors.
The same for the right buttons, including pinned ones on iOS. On Android it also colors the overflow icon (the theme's on-surface-variant color without it).
The shape color behind the icons of the left buttons that have an icon image and no iconBackground.color; the size and corners come from the button's iconBackground, or the icon's size without corners. On iOS only image buttons, not SF Symbols, and without a capsule with the glass design. A color sent by mergeOptions repaints all the side's image buttons, those with their own shape color too.
The color of the disabled left buttons that have no disabledColor of their own. On iOS the text color and the tint of the icon (without it the system dims them); on Android the text and icon tint, light gray by default.
(iOS 16+) The color of the center buttons that have no color of their own, handled like leftButtonColor.
(iOS 16+) The color of the disabled center buttons that have no disabledColor of their own.
Whether the content of the screen goes under the bar, starting at the top of the screen. The screen goes under the bar by itself in some cases (a large title that may show, hideOnScroll, a hidden bar, an explicit translucent background on iOS). A change by mergeOptions applies at once on iOS, on the next layout on Android.
The identifier tests find the bar by: the accessibility identifier of the bar on iOS (without it UIKit gives the title of the screen), the view tag on Android. The text title gets <testID>.title, the subtitle <testID>.subtitle and the large title <testID>.largeTitle. The system title of iOS 26 can't carry an identifier; find it by its text inside the bar. Without the option, the identifier is cleared.
The title: text and font, or a component, and on iOS its menu.
The text of the title. Setting it removes a React title. On iOS it is the title of the screen's navigation item, the label the system shows on the next screen's back button without the glass design, and what Rename edits. On Android it is one line cut with an ellipsis, and also the text of the large title; a title component set together with the text drops the text and the subtitle (with a warning in development).
The size of the font. On iOS the font is built only when some font option is set, on top of the system font of the place; without any, the system picks (and shrinks the title beside a subtitle). On Android it is in sp, following the system font size, 22 by default.
The color of the text. Without it the system color on iOS and the theme's on-surface color on Android.
The font family of the title, built the same way as fontSize.
The slant of the title.
The weight of the title; the nearest face is used.
A React component in place of the text. Text and component exclude each other: the one set last wins, also in mergeOptions. On iOS it is the navigation item's title view, it hides the subtitle, and the title menu works with it; on Android it sits between the button groups, centered vertically, and fades with the row under a large title.
(iOS 16+) Whether the title menu has a Rename item. It turns the title into a field in the bar with the text selected. When editing ends, an empty text restores the old title, an unchanged one does nothing, a new one is written to text and sent as a title-renamed event. The other items the system suggests (Duplicate, Move, Export, Print) are not shown.
(iOS 16+) A file whose card (icon, name, type, size) opens the title menu, even with the card alone. For a file that doesn't exist the card shows no size.
(iOS 26+, glass design) Puts the title on a Liquid Glass capsule like the buttons: 'regular' or 'clear'; 'none' and any other value mean no capsule. A text title and the subtitle are two lines on the capsule; a component title sits on it as it is, the capsule taking its size. Without the glass design (see UIDesignRequiresCompatibility) and on Android it does nothing.
The height of the row of title and buttons, in dp. By default 64, regardless of topBar.height.
The distance from the top of the bar to the row of title and buttons, in dp; the whole row moves, with the back button and the buttons.
How a text title sits: 'center' in the middle of the bar (shifted when it would touch the buttons), 'fill' across the whole room between the buttons from the start; without it from the start, 16 dp from the left buttons, as in Material. A component has its own component.alignment. iOS places the title by topBar.style.
The second line under the title.
The buttons at the leading edge, the first at the edge. The list is replaced as a whole and [] removes the buttons; they take nothing from the lists of the default options or the stack. They replace the back button on both platforms; on Android a first button with an id also removes the arrow. mergeOptions animates the change with animateLeftButtons.
The buttons at the trailing edge, the first at the edge. The list is replaced as a whole. When space runs out iOS first removes the title, then moves right buttons to the overflow; on Android the bar keeps the buttons of the highest priority, and the rest go to the overflow menu.
(iOS 16+) The buttons in the middle of the bar, in the format of the side buttons. A button, or neighbors with the same group, is one group (one capsule). They show in the middle only on iPad with a style of 'browser' or 'editor'; on iPhone, in 'navigator' and while the tab bar of iPad sits in the bar they are in the overflow menu, a section per group, where an icon button needs a text. Toggles and menus of center buttons keep their state.
(iOS 16+) Lets the user customize the center buttons on iPad and Mac, under this name; the system saves the choice. A group is customizable by its group name (several buttons) or by the id of the button; one without a name, or with a taken one, is fixed. The panel opens from the system menu of iPadOS 26 (View, Customize Toolbar). Empty means no customization, always on iPhone. The list of buttons in the options doesn't change and no callback comes.
The overflow menu ("•••" on iOS 16+, the vertical dots on Android): its items come above the buttons the platform moved there, and the overflow button always shows with them. A pick sends a button press with its id. items: [] removes the items. On iOS the menu is built from the options at each opening, and a title is the title of its section; before iOS 16 there is none. On Android the items come first, always in the menu, with icons, destructive and disabled states, checks and submenus, and the overflow takes the place of one button, so the buttons are laid out again.
(iOS 27.1+) Who keeps the space in the vertical bar of iPhone Duo, where tabs and the buttons of the screen share it: 'tabs' keeps the tabs and moves the buttons to the overflow, 'buttons' keeps the buttons and compresses the tabs. Without it the system keeps the tabs. For a pair of screens the option of the primary one counts.
The background of the bar: color, component, translucency, blur.
The look of the bar while the list is at its top edge. Android doesn't read it.
The bar style of the stack. What shows of it on a bar with the current appearance the system decides; the option matters with background.translucent: true only. It doesn't give the status bar its style: the status bar follows statusBar.style of the screen on top.
(iOS 16+) The layout of the bar: 'navigator' centers the title; 'browser' and 'editor' put it next to the back button and leave the middle for the center buttons on iPad. On iOS 26 the two look the same. Without it the system style ('navigator') is left alone.
Whether there is no line under the bar in its usual look. It survives a mergeOptions of the background. At the scroll edge scrollEdgeAppearance.noBorder counts.
The large title.
The height of the row of the bar, in dp. The status bar strip comes on top of it, and a large title and a search below. The row of the title alone is title.height.
The color of the line under the bar. On iOS it is the shadow color of the standard look, the system one without it, and it does nothing with noBorder: true. On Android it is the color of the line of borderHeight, black by default and invisible at height 0. A change by mergeOptions applies at once. At the scroll edge, scrollEdgeAppearance.borderColor.
The height of the line under the bar, in dp.
The shadow of the bar, in dp.
The space above the bar, in dp: the bar starts lower. When the bar is not under the status bar and the status bar shows, its height is added. It also lengthens the way of the show and hide animation.
Whether a change of the left buttons of the shown screen is animated: on iOS the new buttons fade in, but a side with a group of several buttons changes at once; on Android it is a transition of the left bar. On iOS 26 and later the system cross-fades a change of the bar's buttons by itself, also when this is false.
Whether a change of the right buttons of the shown screen is animated, like animateLeftButtons.