Skip to main content

Header

Ore-styled header bar: icon-only back button, a breadcrumb trail, and a close button. Every screen in a stack wears one, so the chrome does not shift as the player moves between screens.

Header

Import​

import { Header } from '@bedrock-core/ore-styled';

Usage​

function Settings(): JSX.Element {
const { back } = useNavigation();

return (
<Header
title={'Settings'}
breadcrumbs={['Server', 'Pricing']}
onBack={() => back()}
onClose={() => closeUi(player)}
/>
);
}

Renders as Settings > Server > Pricing, centered between the two icon buttons.

Props​

PropTypeDefaultDescription
titleDisplayText—The screen's own name, first in the trail. Baked, with breadcrumbs
breadcrumbsDisplayText[][]The trail after the title, joined as title > ... > .... Baked, with title
trailDisplayText—The whole trail as one composed value, in place of title and breadcrumbs, for a trail only known when the screen is shown
onBack(event: PressEvent) => unknown—Press handler for the back control. Omit to hide it — the slot keeps its width, so the title stays centered
backToScreenKey—The screen the back control returns to, in place of onBack: a link rather than a handler
backbooleanfalseA back control that returns wherever the player came from, without naming it
cancelstring—The back control as a modal's labeled dismiss. Only inside a <Form>
onClose(event: PressEvent) => unknown—Press handler for the close control. Omit to hide it

Inherits control props. It already sets marginTop, marginLeft and marginRight to 1 and takes the theme's header background; your own layout props override them.

Which back control​

Three ways out, and which one you can use depends on what the screen knows about where it came from.

PropThe press isUse it when
onBackscriptthe screen is only ever reached one way, from code you own
backToa link to a named screenthe destination is fixed, and the screen should be backable out of even when another addon shows it
backa link to the player's stackthe screen is reachable from several places, or opened by another addon entirely

backTo and back are data the build reads, so a screen shown from its reference can still be left. An onBack handler cannot be described, so it does nothing in a foreign realm.

Inside a modal​

A modal has two controls of its own, its submit and its dismiss, and the dismiss is the only one left to leave the screen with. cancel puts it in the back slot with a word on it, since leaving a form abandons what was typed into it:

<Header title={'Settings'} cancel={'Cancel'} />

The labeled dismiss is wider than the icon back, so a header wearing one leaves its trail less room — which is what trailText(segments, resolve, { back: 'cancel' }) is told.

A trail only known at show time​

title and breadcrumbs are composed by the build in every language, collapsed to the room the bar leaves. Where the trail is decided per player — the addon selected, the entity being edited — compose it instead and pass it as trail, which travels as one form entry:

<Header
trail={trailText([addonName, scopeLabel, entityName], core.translations.forPlayer(player))}
onBack={() => back()}
onClose={() => close()}
/>

Pass trail on every render, empty included: the entry it reserves is part of the screen's shape, and a shape that comes and goes moves every entry after it.

Localized titles​

title and every breadcrumb segment are DisplayText, so each may be a literal string, a .lang key, or a RawMessage:

const { key, raw } = useTranslation(i18n);

<Header
title={key($ => $.settings.title)}
breadcrumbs={[raw($ => $.settings.forPlayer, { name: player.name })]}
onBack={() => back()}
/>

Segments resolve through the active TranslationContext up front; a key nothing resolves falls back to the key itself.

Examples​

Root screen — close only​

Omit onBack on the first screen of a stack. The slot still reserves its width, so the title lands in the same place on every screen.

<Header title={'My Addon'} onClose={() => close()} />

Nested screen with a deep trail​

<Header
title={'Config'}
breadcrumbs={['Server', 'Economy', 'Tax rate']}
onBack={() => back()}
onClose={() => close()}
/>

As a fixed screen header​

Pair it with a Scroll so the header stays put while the content moves.

<Panel flexDirection={'column'} width={'100%'} height={'100%'}>
<Header title={'Shop'} onBack={() => back()} />
<Scroll flexGrow={1} gap={4} padding={8}>
{items.map(item => (
<MenuRow title={item.name} subtitle={item.price} onPress={() => buy(item)} />
))}
</Scroll>
</Panel>

Theme tokens​

Read from theme.components.header:

TokenDefault
padding4
gap4
iconSize15
textStyle.font'minecraftTen'
textStyle.scale1.2
textStyle.color'§0'
textStyle.separator'§8'

Notes​

  • Use the same Header on every screen of a stack so the chrome never jumps.
  • Keep the title short and put context in breadcrumbs — a composed trail gives its middle up first when the row runs out of room.
  • Omit onBack rather than passing a no-op on a root screen; the layout already accounts for the missing control.
  • Prefer key() output over pre-resolved strings so each player reads the trail in their own language.
  • Pair with MenuRow for the list below it — the two are designed as one browse screen.