Barra de la aplicación
Da nombre a la pantalla actual en su borde superior y contiene el camino de vuelta y algunas de las acciones de la pantalla. Su borde inferior se mantiene como el borde de la cabecera de la pantalla, y toma su aspecto desplazado en cuanto el contenido se desplaza por debajo de ella.
- Categoría
- Navegación
- Tokens
comp.app-bar- Nivel
- Base
- Web
tanrei-app-barschedule - SwiftUI
TanreiAppBarschedule - Jetpack Compose
TanreiAppBarschedule - Flutter
TanreiAppBarschedule - React Native
AppBarschedule
Generado a partir de docs/status/status.json, specs/app-bar.spec.json
Los ejemplos de Web y React muestran la especificación actual, en la que los elementos de la barra son botones de solo icono. SwiftUI, Compose, Flutter y React Native van rezagados: todavía ofrecen la revisión anterior, con un componente de botón de icono propio, y sus ejemplos muestran esa revisión hasta que se pongan al día.
Una barra de la aplicación pequeña con un botón para volver y dos acciones
Una barra de la aplicación es una región del diseño de página, no una superposición. Ocupa su altura en la parte superior de la pantalla, el contenido empieza debajo de ella y la barra en sí nunca recibe el foco.
Contiene dos tipos de elemento: un elemento navigation al inicio (atrás, menú o cerrar) y hasta tres elementos action al final. Ambos son tus propios botones de solo icono, cada uno con su etiqueta y su clic o, cuando lleva a algún sitio, su href. La barra los dispone y nunca les cambia el estilo. Cada plataforma los recibe en sus propios slots: hijos con slot="navigation" y slot="actions" en la web, los constructores de vistas navigation y actions en SwiftUI, las lambdas navigationIcon y actions en Compose, leading y actions: en Flutter, y los nodos navigation y actions en React Native.
El título es el nombre de la pantalla y su encabezado. En la web es headline, porque el atributo global title de HTML pondría un tooltip sobre toda la barra.
Desplazada. Mientras haya contenido bajo la barra, esta toma su aspecto desplazado. Conecta la vista con desplazamiento de la pantalla y la barra define scrolled por sí misma: scroll-target en la web (el documento de forma predeterminada), .tanreiAppBarScrollSource() en SwiftUI (aplicado después del .safeAreaInset que contiene la barra), un scrollBehavior conectado con Modifier.nestedScroll en Compose, las notificaciones de desplazamiento de la página en Flutter y useAppBarScroll() en React Native. Sin conexión, define scrolled tú.
Barras del sistema. El color de la barra llega hasta debajo de la barra de estado, del recorte de la cámara o de la barra de título de la ventana que tenga encima. Su contenido queda por debajo de ellas y dentro de los márgenes interiores laterales. La web lee env(safe-area-inset-*), Compose recibe windowInsets (de forma predeterminada, las barras de estado y el recorte horizontal de la pantalla), Flutter lee el margen interior de MediaQuery y SwiftUI coloca la barra con .safeAreaInset(edge: .top). React Native no tiene una API de área segura, y Tanrei no añade ninguna dependencia para ello, así que los márgenes interiores llegan solo por las propiedades. Dale a TanreiProvider los insets de la ventana (si usas react-native-safe-area-context, pásale su useSafeAreaInsets()). La propiedad insets de una barra sustituye los lados que nombra, de modo que una barra que no está en la parte superior de la ventana pasa { top: 0 }.
<!-- El título es headline: el atributo title de HTML mostraría un tooltip sobre la barra. -->
<tanrei-app-bar headline="Bandeja de entrada">
<tanrei-button variant="text" slot="navigation" label="Atrás"><span slot="icon">arrow_back</span></tanrei-button>
<tanrei-button variant="text" slot="actions" label="Buscar"><span slot="icon">search</span></tanrei-button>
<tanrei-button variant="text" slot="actions" label="Más opciones"><span slot="icon">more_vert</span></tanrei-button>
</tanrei-app-bar>
<!-- Un título grande que se contrae a medida que #inbox se desplaza. El título es un h1 salvo que heading-level diga otra cosa. -->
<div style="display: flex; flex-direction: column; block-size: 100dvh">
<tanrei-app-bar size="large" headline="Bandeja de entrada" scroll-target="inbox">
<tanrei-button variant="text" slot="navigation" label="Menú"><span slot="icon">menu</span></tanrei-button>
</tanrei-app-bar>
<main id="inbox" style="flex: 1; overflow: auto">…</main>
</div>
<!-- Un botón que lleva a una página es un enlace: dale un href. Una búsqueda puede ser una acción: su activador de icono. -->
<tanrei-app-bar headline="Pestañas">
<tanrei-button variant="text" slot="navigation" href="/components/" label="Todos los componentes"><span slot="icon">arrow_back</span></tanrei-button>
<tanrei-search slot="actions" bar="icon" presentation="dialog" label="Buscar en la documentación" placeholder="Buscar"
clear-label="Borrar búsqueda" back-label="Atrás"></tanrei-search>
</tanrei-app-bar>
<script type="module">
import '@tanrei/web/components/app-bar';
import '@tanrei/web/components/button';
import '@tanrei/web/components/search';
// Los botones son tuyos: la barra no añade eventos propios.
document.querySelector('[label="Atrás"]').addEventListener('click', () => history.back());
</script>import { AppBar, Button, Search } from '@tanrei/react';
<AppBar headline="Bandeja de entrada">
<Button variant="text" slot="navigation" label="Atrás" onClick={goBack}><span slot="icon">arrow_back</span></Button>
<Button variant="text" slot="actions" label="Buscar" onClick={search}><span slot="icon">search</span></Button>
<Button variant="text" slot="actions" label="Más opciones" onClick={openMore}><span slot="icon">more_vert</span></Button>
</AppBar>
// Un botón que lleva a una página es un enlace: dale un href. Una búsqueda puede ser una acción: su activador de icono.
<AppBar headline="Pestañas">
<Button variant="text" slot="navigation" href="/components/" label="Todos los componentes"><span slot="icon">arrow_back</span></Button>
<Search slot="actions" bar="icon" presentation="dialog" label="Buscar en la documentación" placeholder="Buscar" clearLabel="Borrar búsqueda" backLabel="Atrás" />
</AppBar>import Tanrei
// La barra se coloca en el margen superior del área segura de un NavigationStack cuya barra del sistema está oculta.
// Si isScrolled se deja en nil, sigue a la vista de desplazamiento marcada con .tanreiAppBarScrollSource().
NavigationStack {
ScrollView { InboxRows() }
.safeAreaInset(edge: .top, spacing: 0) {
TanreiAppBar("Bandeja de entrada", size: .large) {
TanreiIconButton("Menú", action: openMenu) { Image(systemName: "line.3.horizontal") }
} actions: {
TanreiIconButton("Buscar", action: search) { Image(systemName: "magnifyingglass") }
}
}
// Después del margen que contiene la barra: un modificador aplicado dentro de él no puede alcanzar la barra.
.tanreiAppBarScrollSource()
.toolbar(.hidden, for: .navigationBar)
}import io.github.chnotchy.tanrei.components.TanreiAppBar
import io.github.chnotchy.tanrei.components.TanreiAppBarDefaults
import io.github.chnotchy.tanrei.components.TanreiIconButton
import io.github.chnotchy.tanrei.primitives.TanreiText
import io.github.chnotchy.tanrei.tokens.TanreiAppBarSize
// Una barra pequeña. Sin scrollBehavior permanece plana.
TanreiAppBar(
title = "Bandeja de entrada",
navigationIcon = { TanreiIconButton(onClick = onBack, contentDescription = "Atrás") { TanreiText("arrow_back") } },
actions = {
TanreiIconButton(onClick = onSearch, contentDescription = "Buscar") { TanreiText("search") }
TanreiIconButton(onClick = onMore, contentDescription = "Más opciones") { TanreiText("more_vert") }
},
)
// Una barra grande que se contrae a medida que la lista se desplaza: conecta el comportamiento en un padre de la vista con desplazamiento.
// pinnedScrollBehavior() es el de una barra pequeña: nunca se contrae, y pasa a scrolled mientras haya contenido debajo.
val scrollBehavior = TanreiAppBarDefaults.collapseScrollBehavior()
Column(Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
TanreiAppBar(title = "Bandeja de entrada", size = TanreiAppBarSize.Large, scrollBehavior = scrollBehavior)
LazyColumn { /* el contenido de la pantalla */ }
}import 'package:tanrei/tanrei.dart';
// Una barra pequeña, en el slot de barra de la aplicación de un scaffold o como primer elemento de un Column.
// Si scrolledUnder se deja en null, sigue al ScrollNotificationObserver más cercano, como hace AppBar.
TanreiAppBar(
leading: TanreiIconButton(onPressed: () => Navigator.of(context).maybePop(), icon: const Icon(AppSymbols.arrowBack), semanticLabel: 'Atrás'),
title: 'Bandeja de entrada',
actions: <Widget>[
TanreiIconButton(onPressed: search, icon: const Icon(AppSymbols.search), semanticLabel: 'Buscar'),
TanreiIconButton(onPressed: openMore, icon: const Icon(AppSymbols.moreVert), semanticLabel: 'Más opciones'),
],
),
// Una barra grande que se contrae con su contenido es un sliver, fijado en la parte superior de su CustomScrollView.
CustomScrollView(
slivers: <Widget>[
TanreiSliverAppBar(title: 'Bandeja de entrada', size: TanreiAppBarSize.large, leading: menuButton),
SliverList.list(children: messages),
],
),import { useState } from 'react';
import { ScrollView, View } from 'react-native';
import { AppBar, IconButton, useAppBarScroll } from '@tanrei/react-native';
// Los márgenes interiores vienen de la propiedad insets de TanreiProvider, o de la de la propia barra.
<AppBar
title="Bandeja de entrada"
navigation={<IconButton accessibilityLabel="Atrás" onPress={goBack}>arrow_back</IconButton>}
actions={
<>
<IconButton accessibilityLabel="Buscar" onPress={search}>search</IconButton>
<IconButton accessibilityLabel="Más opciones" onPress={openMore}>more_vert</IconButton>
</>
}
/>
// Una barra grande que se contrae: conecta la vista de desplazamiento, coloca la barra sobre ella y añade al contenido un relleno igual a la altura de la barra.
const scroll = useAppBarScroll();
const [barHeight, setBarHeight] = useState(0);
<View style={{ flex: 1 }}>
<ScrollView onScroll={scroll.onScroll} scrollEventThrottle={16} contentContainerStyle={{ paddingTop: barHeight }}>
{messages}
</ScrollView>
<View style={{ position: 'absolute', top: 0, left: 0, right: 0 }} onLayout={(e) => setBarHeight((h) => Math.max(h, e.nativeEvent.layout.height))}>
<AppBar size="large" title="Bandeja de entrada" scrollState={scroll.state} navigation={menuButton} />
</View>
</View>Una barra grande con subtítulo y un título centrado
Un botón de navegación que es un enlace y un activador de búsqueda entre las acciones
Anatomía
| Parte | Descripción |
|---|---|
1 container | The bar across the top of the screen. Its color reaches under the system inset above it (status bar, camera cutout, window caption). |
2 navigation · opcional | The navigation item: one icon-only Button at the start (back, menu or close). The product's icon-only Button, not restyled by the bar. |
3 brand · opcional | The product's brand: one link to its first page (or one image), after the navigation item, in a cell as large as an icon button's. It draws one image, the symbol alone, the wordmark alone, the symbol and the wordmark side by side (lockup), or one of the two by the window's width (responsive). |
4 context · opcional | The product's context: one control after the brand (a workspace, a project, a design system), the product's own Button, not restyled by the bar. |
5 title | The screen's name. In the top row for a small bar; under the top row for an expanded large bar, moving into the top row as it collapses. |
6 subtitle · opcional | One line under the title: context for it (an account, a status, when it was edited). |
7 actions · opcional | The action items: up to three icon-only Buttons at the end. The product's icon-only Buttons, not restyled by the bar. |
8 outline | The bar's bottom edge. In the default system it is drawn at rest and while content is under the bar; dividerVisibility scroll draws it only once content has scrolled under the bar. |
Propiedades
| Propiedad | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
size | small | large | "small" | Small puts the title in the one row the bar has; large gives the title a larger row of its own under the top row, which collapses into the top row as the content scrolls. One product uses small on most screens and large on its top-level ones. A design system may add values. |
title | string | "" | The screen's name, and the heading of the screen for assistive technology. |
subtitle | string | "" | One line under the title. Empty draws none. |
titleAlignment | start | center | "start" | Where the title sits in the top row: after the navigation button, or centered on the bar. An expanded large bar's own title row always starts at the start. |
brandHref | string | "" | The address of the product's first page: the brand is a link to it. Empty draws the brand as an image that is not a link. |
brandLabel | string | "" | The product's name: the brand's one accessible name, whichever of its images is shown. Required wherever the bar has a brand. |
brandLayout | lockup | responsive | "lockup" | How the brand's symbol and wordmark stand when the product gives both (APB-21): lockup sets them side by side, comp.app-bar.brand.lockup.gap apart and aligned as comp.app-bar.brand.lockup.alignment says; responsive shows the wordmark while the window is medium or wider and the symbol while it is compact, never both. One image, a symbol alone or a wordmark alone is shown as it is, at every width, under either value. |
scrolled | boolean | false | Whether content lies under the bar. A scrolling view connected to the bar sets it (see platforms); a product without one sets it itself. It selects the bar's scrolled condition, and a large bar is drawn collapsed while it is true. |
dividerVisibility | auto | always | scroll | "auto" | When the bar's bottom edge is drawn. always: at rest and while content is under the bar, so that the edge of the screen's header stands still (an app shell's header, a screen whose content starts right under the bar). scroll: only while content lies under the bar, so that the line itself says the content has moved (the scrolled condition's edge alone). auto takes comp.app-bar.outline.visibility, the design system's answer (always in the default system). The bar's color and elevation follow scrolled under either choice. |
Slots
| Slot | Descripción |
|---|---|
navigation | Holds the navigation item: one icon-only Button at the start. |
brand | The brand as one image: a product's single logo file, drawn comp.app-bar.brand.image.height high. Takes the place of brand-symbol and brand-wordmark where both are given. |
brand-symbol | The brand's symbol: comp.app-bar.brand.symbol.size high alone, or while the window is compact under brandLayout responsive; comp.app-bar.brand.lockup.symbol.size high (the wordmark's height) beside the wordmark in a lockup. |
brand-wordmark | The brand's wordmark, drawn comp.app-bar.brand.wordmark.height high: alone at every width, after the symbol in a lockup, or while the window is medium or wider under brandLayout responsive. |
context | Holds one control of the product's context after the brand: a Button, or a Button that opens a Menu, that says and changes the workspace, the project or the design system the screen is in. The product's own control, not restyled by the bar. |
actions | Holds the action items, up to three icon-only Buttons at the end, in reading order; more belong in an overflow menu the product provides. |
Elementos
Los tipos de elemento que el componente repite. Un fixture enumera sus elementos en orden; cada plataforma nombra cada tipo según su propio estilo.
navigation
The one icon-only Button at the start of the top row (back, menu or close): a Button of the text variant and the medium size with an icon and no label, unless the product sets otherwise, placed in the navigation slot, which the bar lays out and does not restyle.
| Propiedad | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
label | string | "" | Its accessible name ("Back"), as the Button's label. Required. |
| Slot | Descripción |
|---|---|
icon | Its glyph, as the Button's icon slot. A fixture item's content is this glyph. |
| Evento | Descripción |
|---|---|
click | The button was activated, as the Button's click. |
| Especificación | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| Elemento | tanrei-button | TanreiButton | TanreiButton | TanreiButton | Button |
label · Propiedad | label | label | contentDescription | semanticLabel | accessibilityLabel |
click · Evento | click | action | onClick | onPressed | onPress |
| Notas | An icon-only <tanrei-button> child with slot="navigation"; the glyph is its content. | An icon-only TanreiButton in the navigation view builder. | An icon-only TanreiButton in the navigationIcon lambda. | An icon-only TanreiButton given as leading. | An icon-only Button element passed as navigation. |
action
An icon-only Button at the end of the top row, up to three in reading order: a Button of the text variant and the medium size with an icon and no label, unless the product sets otherwise, placed in the actions slot, which the bar lays out and does not restyle.
| Propiedad | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
label | string | "" | Its accessible name ("Search"), as the Button's label. Required. |
| Slot | Descripción |
|---|---|
icon | Its glyph, as the Button's icon slot. A fixture item's content is this glyph. |
| Evento | Descripción |
|---|---|
click | The button was activated, as the Button's click. |
| Especificación | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| Elemento | tanrei-button | TanreiButton | TanreiButton | TanreiButton | Button |
label · Propiedad | label | label | contentDescription | semanticLabel | accessibilityLabel |
click · Evento | click | action | onClick | onPressed | onPress |
| Notas | An icon-only <tanrei-button> child with slot="actions"; the glyph is its content. | An icon-only TanreiButton in the actions view builder. | An icon-only TanreiButton in the actions lambda. | An icon-only TanreiButton in the bar's actions: list. | An icon-only Button element among the actions nodes. |
Estados
Comportamiento
Requisitos en formato EARS. Cada implementación de plataforma se prueba contra estos identificadores. El texto de los requisitos se muestra tal como está en la especificación, en inglés.
| ID | Requisito |
|---|---|
APB-1 | WHILE scrolled is false THE app bar SHALL fill its container with comp.app-bar.flat.container.color, raise it by comp.app-bar.flat.container.elevation and draw its bottom edge comp.app-bar.outline.width thick: in comp.app-bar.scrolled.outline.color WHILE its divider visibility (APB-18) is always, so that the edge stands still whether or not content lies under the bar, and in comp.app-bar.flat.outline.color WHILE it is scroll. |
APB-2 | WHILE scrolled is true THE app bar SHALL fill its container with comp.app-bar.scrolled.container.color, raise it by comp.app-bar.scrolled.container.elevation and draw its bottom edge comp.app-bar.outline.width thick in comp.app-bar.scrolled.outline.color, under either divider visibility (APB-18). |
APB-3 | WHEN scrolled changes THE app bar SHALL change its container color, elevation and bottom edge over comp.app-bar.motion.condition-duration with comp.app-bar.motion.condition-easing, and at once where motion is reduced; WHILE its divider visibility (APB-18) is always the bottom edge SHALL NOT change. |
APB-4 | THE app bar SHALL span the full width of its parent and lay out a top row at least comp.app-bar.container.height.small high: the navigation item comp.app-bar.container.padding-inline from the start edge, the title block, and the action items comp.app-bar.container.padding-inline from the end edge, with comp.app-bar.container.gap between them and comp.app-bar.actions.gap between two actions, each vertically centered in the row; a navigation item SHALL go to the start and action items to the end wherever they stand among the items; WHILE there is no navigation item the title block SHALL start comp.app-bar.title.inset from the start edge, and WHILE there are no action items it SHALL end comp.app-bar.title.inset from the end edge. Right-to-left layouts SHALL mirror the order. |
APB-5 | THE app bar SHALL draw a title in the top row on one line in comp.app-bar.title.typescale.small and comp.app-bar.title.color, and WHILE subtitle is not empty the subtitle on one line below it in comp.app-bar.subtitle.typescale.small and comp.app-bar.subtitle.color, the two vertically centered as a block; each SHALL be truncated at the end with an ellipsis when it does not fit. THE app bar SHALL set the title's letter-spacing, in every size, by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them. |
APB-6 | WHILE titleAlignment is center THE app bar SHALL center the top row's title block on the bar's full width and narrow it equally on both sides, truncating its text, so that it never overlaps the navigation or actions slots, and SHALL center its text; WHILE titleAlignment is start THE app bar SHALL start the title block after the navigation slot (or at comp.app-bar.title.inset) with its text start-aligned. |
APB-7 | WHILE size is large and the bar is expanded THE app bar SHALL be at least comp.app-bar.container.height.large high, SHALL draw no title in its top row, and SHALL draw below the top row the title in comp.app-bar.title.typescale.large and, WHILE subtitle is not empty, the subtitle in comp.app-bar.subtitle.typescale.large, both starting comp.app-bar.title.inset from the start edge, each on one line truncated at the end, the block ending comp.app-bar.container.padding-block-end above the bar's bottom edge. |
APB-8 | WHILE size is large and a scrolling view is connected THE app bar SHALL shrink by the distance the content has scrolled from its top, one for one, from its expanded height to comp.app-bar.container.height.small, the expanded title block moving up with the bar's bottom edge and clipped under the top row; the top row's title SHALL be invisible while the expanded title is wholly visible, fully visible once the bar has collapsed, and in between fade in linearly with the part of the expanded title that is covered. WHEN the content scrolls back toward its top THE app bar SHALL expand the same way. |
APB-9 | WHERE a scrolling view is connected THE app bar SHALL take scrolled from it: true while any content lies under the bar (for a large bar, only once it has fully collapsed) and false when the content is at its top. WHILE size is large and scrolled is true THE app bar SHALL be drawn fully collapsed; WHERE nothing is connected and scrolled is false a large app bar SHALL stay expanded. |
APB-10 | THE app bar SHALL extend its container under the top system inset (status bar, camera cutout, window caption) and SHALL place its content below that inset and inside the left and right insets, so that its color reaches the screen's top edge while no content sits under a system bar or cutout. |
APB-11 | THE app bar SHALL NOT restyle its navigation and action items: each SHALL render as the icon-only Button it is, from its own tokens, and keep its own semantics, and the app bar SHALL NOT be focusable itself, so that focus moves from the navigation item to the action items in reading order. A glyph of an item that the system's icon set marks as mirrored (a navigation item's arrow_back) SHALL be mirrored in a right-to-left layout by the item's own icon helper (BTN-19): that is the icon's own behaviour, not a restyling by the app bar. |
APB-12 | THE app bar SHALL expose title as a heading and subtitle as text read after it, and SHALL expose the title only once WHILE size is large: the expanded title while any of it is visible, the top row's title once the bar has collapsed. |
APB-13 | WHILE title is empty THE app bar SHALL draw no title block (an expanded large bar then has an empty title row) and SHALL expose no heading; IF the app bar holds more than three action items or more than one navigation item THE app bar SHALL still render them, and in debug builds report that the extra actions belong in an overflow menu or that a bar has one navigation button. |
APB-14 | WHEN size names a value that the active design system does not have THE app bar SHALL render with the default value's tokens, and in debug builds report the unknown value. |
APB-15 | WHILE the text size is enlarged THE app bar SHALL grow its rows to hold the title and subtitle lines (its heights are minimums), SHALL keep each on one line truncated at the end, and SHALL NOT scale the navigation and action items it holds. |
APB-16 | THE app bar SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the app bar is shown THE app bar SHALL draw itself for the new direction at once, without a motion of its own, keeping its size and the scroll state it follows. |
APB-17 | THE app bar SHALL lay out its title and its subtitle as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE app bar SHALL still place each and align its lines by the layout direction, not by the text's own, and SHALL cut a title or a subtitle that does not fit (APB-5, APB-7) at the end of its own direction, so that a left-to-right label in a right-to-left layout loses its right end and never its beginning. |
APB-18 | THE app bar SHALL draw its bottom edge (APB-1, APB-2) as its dividerVisibility names: WHILE dividerVisibility is auto, as comp.app-bar.outline.visibility names, which follows sys.behavior.divider-visibility unless a design system sets the app bar apart; WHILE dividerVisibility is always or scroll, as that value names, whatever the tokens say. WHEN dividerVisibility, or the token it follows, changes THE app bar SHALL draw the other form at once, moving no part and keeping the scroll position and focus; WHEN dividerVisibility names a value the app bar does not define THE app bar SHALL treat it as auto and in debug builds report the unknown value. A platform that cannot draw a choice SHALL fall back to the first value, always, and state that in its README. |
APB-19 | WHERE the product gives the app bar a brand (an image in brand, brand-symbol or brand-wordmark) THE app bar SHALL place it at the start of the top row, after the navigation item at comp.app-bar.actions.gap from it, or comp.app-bar.container.padding-inline from the start edge WHILE no navigation item is drawn, with the title block after it at comp.app-bar.container.gap; the brand SHALL take a cell at least the minimum target high and wide, padded at its start and end by half the minimum target less comp.app-bar.brand.symbol.size, its images centred on the row's centre line, so that a symbol stands where an icon button's icon stands and a wordmark keeps that inset from the cell's edges. Right-to-left layouts SHALL mirror the order. |
APB-20 | THE app bar SHALL draw the image in brand comp.app-bar.brand.image.height high, the symbol comp.app-bar.brand.symbol.size high and the wordmark comp.app-bar.brand.wordmark.height high, each as wide as its own proportions make it, and SHALL give the brand comp.app-bar.brand.color, which an image drawn in the current color takes and an image of its own colors keeps. WHILE the brand is a lockup THE app bar SHALL draw the symbol and then the wordmark in one row, comp.app-bar.brand.lockup.gap apart, aligned in the row's block axis as comp.app-bar.brand.lockup.alignment names (center, start or end). |
APB-21 | WHERE the brand holds one image, a symbol alone or a wordmark alone THE app bar SHALL show it at every window width. WHERE it holds both a symbol and a wordmark, WHILE brandLayout is lockup THE app bar SHALL show both as a lockup (APB-20), and WHILE brandLayout is responsive THE app bar SHALL show the wordmark WHILE the window class is medium or expanded and the symbol WHILE it is compact, never both: the window class of the app shell the bar stands in, or, outside one, the window's width against sys.breakpoint.medium. WHEN the window class changes THE app bar SHALL show the other at once, without a motion of its own, the brand's link and its focus unchanged. |
APB-22 | THE app bar SHALL expose the brand as one link to brandHref named by brandLabel — or, WHILE brandHref is empty, as one image named by brandLabel — between the navigation item and the action items in reading order, and SHALL hide the brand's images from assistive technology, so that the product's name is read once whichever arrangement is shown. THE brand's link SHALL be a stop in the tab order and SHALL draw the focus indicator around its cell, in the shape comp.app-bar.brand.shape. |
APB-23 | IF brandLayout names a value the app bar does not define THE app bar SHALL treat it as lockup and in debug builds report it; IF brand holds an image together with brand-symbol or brand-wordmark THE app bar SHALL show the image in brand alone and in debug builds report the others; IF the bar has a brand and brandLabel is empty, or a brand slot holds more than one image, THE app bar SHALL still draw what it holds and in debug builds report what is missing or extra. |
APB-24 | WHILE the brand is a lockup THE app bar SHALL draw the symbol comp.app-bar.brand.lockup.symbol.size high, which is the wordmark's height (comp.app-bar.brand.wordmark.height) unless a design system sets it apart, so that the symbol and the wordmark stand at one height; a symbol shown alone keeps comp.app-bar.brand.symbol.size. |
APB-25 | WHERE the product puts a control in context THE app bar SHALL place it at the start of the top row after the brand, at comp.app-bar.actions.gap from the brand's cell (from the navigation item WHILE no brand is drawn, and comp.app-bar.container.padding-inline from the start edge WHILE neither is), vertically centred in the row, with the title block after it at comp.app-bar.container.gap; SHALL NOT restyle it, as APB-11 says of the navigation and action items; and SHALL keep it in reading order after the brand and before the title block and the action items. Right-to-left layouts SHALL mirror the order. |
Correspondencia de nombres por plataforma
Paridad no significa API idénticas. Cada plataforma expresa el mismo contrato con su propio estilo.
| Especificación | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| Componente | tanrei-app-bar | TanreiAppBar | TanreiAppBar | TanreiAppBar | AppBar |
size · Propiedad | size | size | size | size | size |
title · Propiedad | headline | title | title | title | title |
subtitle · Propiedad | subtitle | subtitle | subtitle | subtitle | subtitle |
titleAlignment · Propiedad | titleAlignment | titleAlignment | titleAlignment | centerTitle | titleAlignment |
brandHref · Propiedad | brandHref | brandHref | brandHref | brandHref | brandHref |
brandLabel · Propiedad | brandLabel | brandLabel | brandLabel | brandLabel | brandLabel |
brandLayout · Propiedad | brandLayout | brandLayout | brandLayout | brandLayout | brandLayout |
scrolled · Propiedad | scrolled | isScrolled | scrollBehavior | scrolledUnder | scrolled |
dividerVisibility · Propiedad | dividerVisibility | dividerVisibility | dividerVisibility | dividerVisibility | dividerVisibility |
| Notas | title is the headline property and attribute, because HTML's global title attribute would show a tooltip over the whole bar. titleAlignment is the title-alignment attribute. The slots are navigation, context and actions. A web-only scroll-target attribute names the id of the scrolling element to connect (default: the document's scrolling element; none connects nothing), from which the bar sets scrolled itself. A web-only heading-level (default 1) sets the title's heading level. Insets are env(safe-area-inset-top|left|right). dividerVisibility is the divider-visibility attribute (auto, always, scroll); auto reads --tanrei-comp-app-bar-outline-visibility from the cascade with a style query, and where the browser has none the bar writes the name it read on its container when it renders. The brand: brand-href, brand-label and brand-layout (lockup | responsive); its images are children with slot="brand", slot="brand-symbol" or slot="brand-wordmark" (an <img> or an inline <svg>), which the bar sizes from its tokens, marks aria-hidden and draws inside its own link (part="brand"). The link is the bar's: a router that follows links by their clicks reads it from the click's composed path. The window class is the enclosing <tanrei-app-shell>'s, else matchMedia against sys.breakpoint.medium. | TanreiAppBar(_ title:, subtitle:, size:, titleAlignment:, isScrolled: Bool? = nil) { navigation } actions: { … }, placed with .safeAreaInset(edge: .top) in a NavigationStack whose system bar is hidden; the system bar's heights, title font and edge cannot be set from the tokens. Hiding it must not lose the interactive back swipe: the implementation keeps it working. The connected scroll view is the one marked .tanreiAppBarScrollSource(), applied after the .safeAreaInset that holds the bar (the inset's content sees only the environment where the inset is applied); it connects on iOS 18 and macOS 15 and later. isScrolled: nil follows it, a value overrides it. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). | Compose idiom (as TopAppBar): TanreiAppBar(title, navigationIcon = { … }, actions = { … }, subtitle, size, titleAlignment, scrollBehavior, windowInsets). scrollBehavior (TanreiAppBarDefaults.pinnedScrollBehavior() for small, .collapseScrollBehavior() for large) is connected with Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), and its state carries scrolled and the collapse; without one the bar is flat and expanded, and a state created with a given offset draws the scrolled fixtures. windowInsets defaults to the status bars plus the horizontal display cutout. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). | Flutter idiom (as AppBar and SliverAppBar.large): TanreiAppBar is a PreferredSizeWidget for Scaffold.appBar, with leading, actions, title (a String), subtitle, size and centerTitle (true for center). scrolledUnder: null follows the ScrollNotifications of the scaffold's body, as AppBar's scrolled-under state does; a bool overrides it. A large bar that collapses is TanreiSliverAppBar inside a CustomScrollView. Insets through SafeArea/MediaQuery.padding. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). | navigation and actions are React nodes (an icon-only Button, and a fragment of up to three). The scroll connection is a hook: const scroll = useAppBarScroll() gives scroll.onScroll for a ScrollView or FlatList and scroll.state for the bar's scrollState prop, which sets scrolled and the collapse; without it the bar draws what scrolled says. Insets come from the bar's own insets prop, side by side, falling back to TanreiProvider's insets; the package takes no safe-area dependency, and a product that uses react-native-safe-area-context passes its useSafeAreaInsets() to either. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). |
Tokens
| Token | Alias de | Valor resuelto (claro) |
|---|---|---|
--tanrei-comp-app-bar-actions-gap | sys.target.spacing | 8px |
--tanrei-comp-app-bar-brand-color | sys.color.on-surface | |
--tanrei-comp-app-bar-brand-image-height | comp.app-bar.brand.wordmark.height | 40px |
--tanrei-comp-app-bar-brand-lockup-alignment | — | 0 |
--tanrei-comp-app-bar-brand-lockup-gap | sys.space.space100 | 8px |
--tanrei-comp-app-bar-brand-lockup-symbol-size | comp.app-bar.brand.wordmark.height | 40px |
--tanrei-comp-app-bar-brand-shape | sys.shape.corner.full | 9999px |
--tanrei-comp-app-bar-brand-symbol-size | sys.icon.medium | 24px |
--tanrei-comp-app-bar-brand-wordmark-height | — | 40px |
--tanrei-comp-app-bar-container-gap | sys.space.space100 | 8px |
--tanrei-comp-app-bar-container-height-large | — | 120px |
--tanrei-comp-app-bar-container-height-small | — | 64px |
--tanrei-comp-app-bar-container-padding-block-end | sys.space.space150 | 12px |
--tanrei-comp-app-bar-container-padding-inline | sys.space.space50 | 4px |
--tanrei-comp-app-bar-flat-container-color | sys.color.surface | |
--tanrei-comp-app-bar-flat-container-elevation | sys.elevation.level0 | |
--tanrei-comp-app-bar-flat-outline-color | — | |
--tanrei-comp-app-bar-motion-condition-duration | sys.motion.role.state.large | 250ms |
--tanrei-comp-app-bar-motion-condition-easing | sys.motion.easing.state | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-app-bar-outline-visibility | sys.behavior.divider-visibility | 0 |
--tanrei-comp-app-bar-outline-width | sys.border.hairline | 1px |
--tanrei-comp-app-bar-scrolled-container-color | sys.color.surface | |
--tanrei-comp-app-bar-scrolled-container-elevation | sys.elevation.level0 | |
--tanrei-comp-app-bar-scrolled-outline-color | sys.color.outline-variant | |
--tanrei-comp-app-bar-subtitle-color | sys.color.on-surface-variant | |
--tanrei-comp-app-bar-title-color | sys.color.on-surface | |
--tanrei-comp-app-bar-title-inset | sys.space.space200 | 16px |
--tanrei-comp-app-bar-subtitle-typescale-large | sys.typescale.body | 400 14px/1.5714 |
--tanrei-comp-app-bar-subtitle-typescale-small | sys.typescale.body-small | 400 13px/1.5385 |
--tanrei-comp-app-bar-title-typescale-large | sys.typescale.heading-1 | 500 32px/1.25 |
--tanrei-comp-app-bar-title-typescale-small | sys.typescale.heading-4 | 500 18px/1.4444 |
Fixtures
Representaciones canónicas. Todas las plataformas capturan cada fixture con el mismo identificador para poder comparar los resultados.
size: small (10)
small
title: Inbox items: 3 small-scrolled
title: Inbox scrolled: true items: 3 small-center
title: Inbox titleAlignment: center items: 3 small-subtitle
title: Quarterly report subtitle: Edited 5 minutes ago items: 2 small-title-only
title: Settings small-brand
brandHref: / brandLabel: Tanrei items: 2 slots: brand small-brand-symbol
title: Inbox brandHref: / brandLabel: Tanrei items: 2 slots: brand-symbol small-brand-wordmark
brandHref: / brandLabel: Tanrei items: 2 slots: brand-wordmark small-brand-lockup
brandHref: / brandLabel: Tanrei items: 2 slots: brand-symbol, brand-wordmark small-brand-responsive
brandHref: / brandLabel: Tanrei brandLayout: responsive items: 2 slots: brand-symbol, brand-wordmark size: large (3)
large
size: large title: Inbox items: 3 large-subtitle
size: large title: Inbox subtitle: [email protected] items: 3 large-scrolled
size: large title: Inbox scrolled: true items: 3 Generado a partir de specs/app-bar.spec.json, tokens/comp/app-bar.tokens.json, design/tokens/
Usa una barra de la aplicación en la parte superior de una pantalla para decir dónde está la persona, para llevarla atrás o abrir el menú, y para dar acceso a las pocas acciones que pertenecen a toda la pantalla: buscar, compartir, la cuenta. Una pantalla tiene una sola barra de la aplicación.
Usa una barra de navegación o un panel de navegación para moverte entre los destinos de nivel superior de una aplicación. El botón de menú de la barra de la aplicación puede abrir un panel de navegación modal. Tanrei no tiene barra de la aplicación inferior: las acciones en la parte inferior de una pantalla compacta son tarea de la barra de herramientas.
| Opción | Qué hace | Úsala para |
|---|---|---|
| Small (predeterminado) | Una fila: el botón de navegación, el título y las acciones. | La mayoría de las pantallas, y toda pantalla a la que se llega desde otra. |
| Large | Un título más grande en una fila propia bajo la fila superior. A medida que el contenido se desplaza, se contrae dentro de la fila superior, al mismo ritmo que el desplazamiento, y el título de la fila superior aparece con un fundido. Vuelve a expandirse cuando el contenido regresa a su inicio. | Las pantallas de nivel superior de un producto, donde el título es también el punto de referencia de la pantalla. |
titleAlignment start (predeterminado) |
El título sigue al botón de navegación. | La mayoría de las barras. |
titleAlignment center |
El título se centra respecto a toda la barra y se estrecha por igual a ambos lados, de modo que nunca queda debajo de los botones. | Productos que siguen los títulos centrados de iOS. Un título grande expandido siempre empieza en el inicio. |
Un sistema de diseño puede añadir tamaños. En SwiftUI, Compose, Flutter y React Native, un tamaño más alto que small recibe una fila de título propia, como large. En la web, la recibe cada tamaño que añade el sistema de diseño. El preajuste m3-like todavía no tiene el tamaño medium de Material.
- El borde inferior se mantiene. En el sistema predeterminado la barra dibuja una línea fina en su borde inferior en reposo y mientras hay contenido debajo. La barra es el borde de una región que no se mueve, como la cabecera de una estructura de la aplicación, así que su línea no aparece ni desaparece con el desplazamiento.
- O sigue al desplazamiento. Define
dividerVisibilitycomoscroll(divider-visibilityen la web) para dibujar el borde solo cuando hay contenido debajo de la barra, de modo que la propia línea diga que el contenido se ha movido. Un sistema de diseño toma esa decisión para todas las barras, hojas y diálogos consys.behavior.divider-visibility, o solo para las barras concomp.app-bar.outline.visibility.cupertinoym3-likeeligenscroll, como hacen sus originales. - Plana y desplazada. Mientras el contenido está en su inicio, la barra permanece plana. En cuanto hay contenido debajo, la barra toma su aspecto desplazado: en
m3-like, un contenedor teñido; encupertino, uno relleno. El cambio se suaviza con el movimiento de condición de la barra y ocurre de inmediato cuando el movimiento está reducido. - Una barra grande solo está desplazada cuando se ha contraído del todo. Hasta entonces, la propia contracción muestra que el contenido se ha movido.
- La barra se queda en su sitio. No se oculta mientras el contenido se desplaza hacia abajo. Ese es un comportamiento de desplazamiento de la pantalla, no de la barra.
- Dale a la barra un solo botón de navegación como máximo: atrás en una pantalla a la que se llegó desde otra, menú en una pantalla de nivel superior, cerrar en una tarea a pantalla completa.
- No pases de tres acciones. Pon el resto en un menú de desbordamiento: un botón de icono «Más opciones» que abre un menú de Tanrei. Las compilaciones de depuración avisan de una cuarta acción y de un segundo botón de navegación, y aun así los dibujan.
- Los botones se ven como en cualquier otro lugar. La barra los dispone y nunca les cambia el color.
- Un botón que lleva a algún sitio es un enlace: dale un
href. Un botón para volver que lleva a la página superior, o una acción de ayuda que abre una página, es entonces un enlace real, dibujado como el mismo botón. Un botón para volver que retrocede por el historial sigue siendo un botón. - En la web, una búsqueda puede ser una de las acciones en forma de activador de icono (
barenicon): un botón de solo icono que abre el diálogo o la vista a pantalla completa de la búsqueda.
Un producto puede poner su logo en la barra como el enlace a su primera página. Da a la barra la dirección (brandHref, brand-href en la web) y el nombre del producto (brandLabel): la barra dibuja un solo enlace, con ese nombre, alrededor de las imágenes que le des, y oculta las imágenes a las tecnologías de apoyo, de modo que el nombre se lee una sola vez. Coloca la marca después del botón de navegación, en una celda tan grande como la de un botón de icono, y le da comp.app-bar.brand.color salvo que tus imágenes tengan colores propios.
- Una imagen. Un único archivo de logo en
slot="brand", dibujado acomp.app-bar.brand.image.heightde alto. - Solo el símbolo. En
slot="brand-symbol", dibujado acomp.app-bar.brand.symbol.sizede alto, donde está el icono de un botón de icono. - Solo el logotipo. En
slot="brand-wordmark", dibujado acomp.app-bar.brand.wordmark.heightde alto. - El símbolo y el logotipo juntos. Da los dos. Por defecto (
brandLayoutenlockup) quedan uno junto al otro, acomp.app-bar.brand.lockup.gapde distancia y alineados como indicacomp.app-bar.brand.lockup.alignment. El símbolo tiene entonces la altura del logotipo (comp.app-bar.brand.lockup.symbol.size). - Según el ancho de la ventana. Da los dos y pon
brandLayoutenresponsive(brand-layouten la web): la barra muestra el logotipo mientras la ventana es medium o más ancha y el símbolo mientras es compact, nunca los dos. Dentro de un app shell sigue la clase de ventana del shell.
La barra da tamaño a cada imagen y conserva sus proporciones. No uses el título para el nombre del producto: el título es el nombre de la pantalla. SwiftUI, Compose, Flutter y React Native todavía no dibujan la marca.
La cabecera de este sitio muestra solo el logotipo de Tanrei, en todos los anchos.
- Escribe el título como el nombre de la pantalla, por ejemplo «Bandeja de entrada» o «Informe trimestral». Que sea corto: ocupa una sola línea y se corta con puntos suspensivos.
- Usa el subtítulo para un contexto que ayude a distinguir dos pantallas parecidas: una cuenta, un estado, cuándo se editó.
- Elige un tamaño para todas las pantallas de nivel superior y otro para todas las demás.
- No pongas en los slots nada que no sean botones de icono: ni un campo de texto, ni un campo de búsqueda, ni pestañas, ni un control segmentado. Una fila de pestañas va debajo de la barra, y una vista de pestañas situada más abajo puede vincularse a ella.
- No pongas en la barra una acción principal como «Crear». Usa un botón de acción principal.
- No le des al título una segunda línea ni lo conviertas en un enlace.
- Rol
none- Etiquetado
- The title is the screen's heading (a level 1 heading on the web unless the product sets another level). The subtitle is read after it. The navigation and action items, and the control in context, are named by their own labels. The brand is one link to the product's first page named by brandLabel (the product's name), whichever of its images is shown; its images are hidden from assistive technology.
- Objetivo mínimo
- El área de pulsación cumple el tamaño mínimo de objetivo aunque el tamaño visual sea menor. minimum 32px · pointer 44px · spacing 8px · touch 48px
Teclado
| Teclas | Acción |
|---|---|
| Tab | Moves focus to the navigation item, then to the brand's link, then to the control in context, then through the action items; the bar itself is not a tab stop. |
Notas
- The app bar has no role of its own and takes no input: its buttons are the product's icon-only Buttons, which meet the minimum target themselves (BTN-5). The bar is not a landmark, because only the product knows whether it is its page's banner; a product that wants one wraps the bar in its own header element.
- The title is truncated rather than wrapped even at 200% text size: the bar's rows grow with the text, but a bar of several lines would push the screen's content away. The full title stays available to assistive technology.
- Where both titles of a large bar are partly visible, only the expanded one is exposed, so the heading is never read twice.
Generado a partir de specs/app-bar.spec.json, tokens/sys/measure.tokens.json
- La barra no tiene un rol propio y nunca puede recibir el foco. Tab pasa del botón de navegación a las acciones y las recorre en el orden de lectura. Cada botón conserva su rol, su nombre y su objetivo mínimo, y un botón con
hrefse expone como un enlace. - El título se expone como el encabezado de la pantalla: un encabezado de nivel 1 en la web, salvo que
heading-leveldiga otra cosa. El subtítulo se lee después. Un título vacío no dibuja nada y no expone ningún encabezado. - Una barra grande dibuja dos títulos mientras se contrae, pero solo expone uno: el título expandido mientras alguna parte de él sea visible, y el de la fila superior cuando la barra se ha contraído. El encabezado nunca se lee dos veces.
- La barra no es una región de referencia (landmark). Solo tú sabes si es el banner de la página.
- Un texto más grande hace crecer las filas de la barra, cuyas alturas son mínimas. El título y el subtítulo se mantienen en una línea y se truncan en lugar de saltar de línea, incluso al 200%, de modo que la barra nunca empuja el contenido. El título completo sigue disponible para la tecnología de apoyo. Los botones de icono no se escalan.
- La barra toma su dirección del lugar donde se usa. En un diseño de derecha a izquierda se refleja: el botón de navegación queda a la derecha y las acciones, a la izquierda. Un glifo que el conjunto de iconos marca como reflejado, como una flecha de retroceso, lo refleja su propio botón, no la barra.
- El título y el subtítulo se componen como texto con su propia dirección, aislado del texto que lo rodea. Un nombre de izquierda a derecha en un diseño de derecha a izquierda conserva su orden, y se corta por su propio final, nunca por su principio.
- Las compilaciones de depuración avisan de más de tres acciones, de más de un botón de navegación y de un tamaño que el sistema de diseño no tiene.
Carencias conocidas por plataforma:
- SwiftUI, Compose, Flutter y React Native:
dividerVisibilityespera a que esas plataformas se pongan al día. Dibujan el borde inferior solo cuando hay contenido debajo de la barra, como hacescroll. - SwiftUI, Compose, Flutter y React Native: las reglas de derecha a izquierda (un glifo reflejado donde el conjunto de iconos lo marca, un título compuesto en su propia dirección) esperan a que esas plataformas se pongan al día, igual que un botón con
href. - Web: todos los tamaños siguen a
rem, así que un tamaño de texto mayor en el navegador hace crecer los botones de icono junto con el texto. Ampliar solo la tipografía de Tanrei no lo hace. - Web: una barra grande que sigue el desplazamiento del propio documento y está en
position: stickydentro del flujo del documento mueve el contenido tanto por su contracción como por el desplazamiento, de modo que el contenido se mueve el doble de rápido mientras la barra se contrae. Coloca una barra que se contrae encima de un elemento con desplazamiento (scroll-target) o en una cabecera fija. - Web: cada botón de icono ocupa una celda del objetivo mínimo del puntero en uso, 44 para un ratón, así que dos acciones quedan a 52 de centro a centro donde Compose y Flutter, que miden el objetivo táctil de 48, las dibujan a 56.
- SwiftUI: la barra sigue a su vista de desplazamiento solo a partir de iOS 18 y macOS 15. Antes de eso no hay nada conectado, y la barra dibuja lo que dice
isScrolled. - SwiftUI:
isScrolled: trueen una barra grande conectada la dibuja contraída, pero conserva su altura expandida en el diseño, así que se ve un hueco encima del contenido mientras este está en su inicio. - SwiftUI: con la barra del sistema oculta, la barra mantiene en funcionamiento el gesto de deslizar desde el borde para volver sustituyendo el delegado del gesto de retroceso del controlador de navegación. Esto solo se ha comprobado en iOS 26.5. Que una barra grande expone un solo título a la vez todavía no se ha comprobado con VoiceOver.
- Flutter: un
TanreiAppBargrande no se contrae con su contenido, porque un widget de caja no puede encogerse con la vista de desplazamiento que tiene debajo. Ignora las notificaciones de desplazamiento, permanece expandido y solo se dibuja contraído mientrasscrolledUnderes true. UsaTanreiSliverAppBarpara una barra que se contrae. - Flutter:
preferredSizeinforma de una altura ilimitada, porque no puede leer el tema. Un scaffold deja que la barra se dimensione sola, pero tu propio diseño no puede usar ese número. - Compose: la contracción se detiene donde se detiene el desplazamiento, así que una barra grande puede quedar a medio contraer. No se abre ni se cierra de golpe tras un lanzamiento, como hace la de Material. La especificación no pide ese ajuste.
- React Native: para que una barra grande se contraiga al mismo ritmo que su contenido, colocas la barra sobre la vista de desplazamiento y añades al contenido un margen interior igual a la altura de la barra, como hace el ejemplo anterior. La contracción, los márgenes interiores y lo que anuncian los lectores de pantalla todavía no se han comprobado en un dispositivo.
- Todas las plataformas: con
cupertino, la fila superior de 44 puntos crece hasta 48 cuando contiene botones de icono, porque su objetivo táctil es 48 y el objetivo mínimo prevalece. En la web solo crece con un puntero grueso, ya que el objetivo de un ratón es 44. La fila expandida de una barra grande es además 1 punto más alta que la altura del contenedor de cupertino. - Todas las plataformas: con subtítulo, el título expandido queda cubierto antes de que la barra se haya contraído del todo. La especificación todavía no dice qué título se expone entretanto. Todas las plataformas pasan el encabezado a la fila superior en cuanto el título expandido queda cubierto.
- Dale un título a cada barra. Es el encabezado de la pantalla.
- Dale una etiqueta a cada botón de icono, como «Atrás» o «Buscar».
- En la web, define
heading-levelcuando la página ya tenga un encabezado de nivel 1, y envuelve la barra en un<header>cuando sea el banner de la página. - Conecta la vista con desplazamiento de la pantalla, o define
scrolledtú, para que la barra muestre cuándo hay contenido debajo. - En React Native, pasa los márgenes interiores de la ventana a
TanreiProvider. En React Native y Compose, una barra que no está en la parte superior de la ventana recibe márgenes interiores distintos (insets={{ top: 0 }}, o tus propioswindowInsets). - Escribe títulos cortos. Un título cortado con puntos suspensivos se sigue leyendo completo, pero quienes ven la pantalla solo ven su comienzo.