Saltar al contenido
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
Primeros pasosWebReactSwiftUIJetpack ComposeFlutterReact NativePreajustesTu propio sistema de diseñoUsar Tanrei con agentes de IAMarcaTokens de diseñoSistemas de diseño y personalizaciónTheme StudioColorTipografíaIconosFormaElevaciónMovimientoEstados de interacciónComportamientoDiseño de páginaAccesibilidadTextosTokens de colorTokens de la escala tipográficaTokens de formaTokens de elevaciónTokens de movimientoTokens de estadoTokens de espacio y de medidaComponentesBotónBotón de acción principalBotón segmentadoGrupo de botonesBotón con menúBarra de herramientasBotón de copiarCasilla de verificaciónBotón de opciónInterruptorChipMenúControl deslizanteCampo de control deslizanteCalendarioDateTimePickerGrupo de camposGrupo de botones de opciónGrupo de casillas de verificaciónSelectCampo de selecciónBarra de menúsSubida de archivosSelector de archivos AvanzadoZona de soltar archivosEntrada de texto AvanzadoCampo de textoCampo de chipsCampoCuadro combinado AvanzadoCampo de cuadro combinadoEntrada numérica AvanzadoCampo numéricoEntrada de color AvanzadoCampo de colorEntrada de código de un solo uso AvanzadoCampo de código de un solo usoEntrada de texto incrustada AvanzadoCuadro de redacción de chatTarjetaDivisorCapa modal AvanzadoDiálogoListaFila de listaHoja inferiorHoja lateralCarruselBloque de códigoTablaPopoverPasosAcordeónLista de descripcionesFiguraEstructura de la aplicaciónCabecera de páginaVista de árbolLínea de tiempoVista previa de imágenesTirador de tamañoMarco redimensionableÁrea de desplazamientoInsigniaIndicador de progresoMedidorContador animadoIndicador de cargaSnackbarTooltipAtajo de tecladoTagCódigo en líneaCalloutAvatarEstado vacíoGrupo de tagsEsqueletoElemento de archivoMuestraTexto en marquesinaPestañasVista de pestañasBarra de la aplicaciónBarra de navegaciónPanel de navegaciónBúsquedaEnlacePaginaciónEnlaces anterior y siguienteIndicador de pasosRuta de navegaciónTabla de contenidoTarjeta de enlaceMenú FABEstadoCómo se construye TanreiCómo contribuirLicencia y atribución
InicioComponentesSnackbar

Snackbar

Informa brevemente a la persona, en el borde inferior de la pantalla o en su extremo superior final, de lo que la aplicación acaba de hacer, con una acción como máximo, sin tomar el foco ni interrumpir su trabajo.

content_copyVer en Markdown
Categoría
Comunicación
Tokens
comp.snackbar
Nivel
Base

Descripción general

Web
tanrei-snackbar
schedule
SwiftUI
TanreiSnackbar
schedule
Jetpack Compose
TanreiSnackbar
schedule
Flutter
TanreiSnackbar
schedule
React Native
Snackbar
schedule

Generado a partir de docs/status/status.json, specs/snackbar.spec.json

Una especificación revisada que aún no está en todas las plataformas

Esta página describe el snackbar tal como lo define ahora la especificación: una barra dibujada sobre una superficie del esquema o en inverso, una acción tonal discreta, formas de estado en tintes discretos, un título y un texto que se expande. La web lo dibuja todo. Arriba sigue marcado como rezagado hasta que se revisen sus formas de estado en inverso y se registren sus imágenes de referencia. SwiftUI, Compose, Flutter y React Native ofrecen una revisión anterior, con una acción de texto y sin formas de estado, sin título, sin expansión y sin inverse, y sus ejemplos muestran esa revisión hasta que se pongan al día. Las demostraciones son el componente web tal como se distribuye hoy.

Dibujado dentro de la página: un mensaje con una acción y otro con un botón de cierre

Uso

Un snackbar no se coloca. Le pides a un anfitrión que muestre uno, y el anfitrión lo pone en cola, lo sitúa en la parte inferior de su área o en su extremo superior final, controla su tiempo de espera y lo anuncia. show se resuelve una vez que ese snackbar se ha cerrado: con action cuando se activó su acción, o con dismiss y el motivo. Así, el código de «deshacer» se lee de arriba abajo.

Plataforma El anfitrión Mostrar un snackbar
Web <tanrei-snackbar-host>, colocado como último elemento de la página host.show(options), una promesa
SwiftUI un TanreiSnackbarHost, unido con .tanreiSnackbarHost(_:) await host.show(message:…)
Compose TanreiSnackbarHost(hostState), el último en un Box junto con el contenido hostState.showSnackbar(message, …), una llamada de suspensión
Flutter TanreiSnackbarMessenger, alrededor de la página sobre la que informa TanreiSnackbarMessenger.of(context).show(TanreiSnackbar(…)), un controlador cuyo closed es un future
React Native lo renderiza TanreiProvider en su capa de superposición useSnackbar().show(options), una promesa

Cada anfitrión también cierra el snackbar que se está mostrando (dismissCurrent) y además descarta los que esperan (clear), en ambos casos con el motivo host. Un elemento snackbar dibujado fuera de un anfitrión se dibuja allí donde está, centrado en el ancho que se le da, igual que lo centra un anfitrión (o al final de ese ancho cuando su placement es top-end): sin tiempo de espera, cola, entrada ni anuncio. Esa forma es para páginas de documentación y pruebas, como la demostración de arriba.

<!-- El último de la página: el lugar del anfitrión en el orden del foco es donde están los controles del snackbar. -->
<tanrei-snackbar-host></tanrei-snackbar-host>

<script type="module">
  import '@tanrei/web/components/snackbar';
  const snackbars = document.querySelector('tanrei-snackbar-host');

  async function archive() {
    await archiveConversation();
    // Se resuelve una vez cerrado: { result: 'action' } o { result: 'dismiss', reason }.
    const { result } = await snackbars.show({ message: 'Conversación archivada', action: 'Deshacer' });
    if (result === 'action') await restoreConversation();
  }

  // Una forma de estado: el glifo, y el estado en palabras para la tecnología de apoyo.
  snackbars.show({
    status: 'error',
    statusLabel: 'Error',
    title: 'Mensaje no enviado',
    message: 'No tienes conexión. El mensaje se quedará en la Bandeja de salida.',
    action: 'Reintentar',
    expandLabel: 'Mostrar el mensaje completo',
  });

  // Dibujado en inverso, elija lo que elija el sistema de diseño. Omite `inverse` para tomar la elección del sistema.
  snackbars.show({ message: 'Enlace copiado', inverse: true });
</script>
import { useRef } from 'react';
import { SnackbarHost } from '@tanrei/react';
import type { TanreiSnackbarHost } from '@tanrei/web';

// La ref es el elemento: show() es un método suyo.
const snackbars = useRef<TanreiSnackbarHost>(null);

async function archive() {
  await archiveConversation();
  const { result } = await snackbars.current!.show({ message: 'Conversación archivada', action: 'Deshacer' });
  if (result === 'action') await restoreConversation();
}

// Una forma de estado, con un título encima del mensaje.
snackbars.current?.show({ status: 'error', statusLabel: 'Error', title: 'Mensaje no enviado', message: 'No tienes conexión.', action: 'Reintentar' });

// Dibujado en inverso, elija lo que elija el sistema de diseño.
snackbars.current?.show({ message: 'Enlace copiado', inverse: true });

// El último de la página, después del contenido.
<SnackbarHost ref={snackbars} />
import Tanrei

@State private var snackbars = TanreiSnackbarHost()

// Une el anfitrión a la vista cuyo borde inferior usa. Se dibuja en una superposición, no en una hoja.
ContentView()
    .tanreiSnackbarHost(snackbars)

// Devuelve el resultado una vez cerrado el snackbar: .action o .dismissed(reason).
// Una petición a un anfitrión cuya vista no está en pantalla espera hasta que lo esté.
let result = await snackbars.show(message: "Conversación archivada", actionLabel: "Deshacer")
if case .action = result { restoreConversation() }
import io.github.chnotchy.tanrei.components.TanreiSnackbarHost
import io.github.chnotchy.tanrei.components.TanreiSnackbarHostState
import io.github.chnotchy.tanrei.components.TanreiSnackbarResult

// Como el SnackbarHostState de Material: showSnackbar se suspende hasta que el snackbar se ha cerrado.
val snackbars = remember { TanreiSnackbarHostState() }
val scope = rememberCoroutineScope()
Box(Modifier.fillMaxSize()) {
    Content(onArchive = {
        scope.launch {
            when (snackbars.showSnackbar("Conversación archivada", actionLabel = "Deshacer")) {
                TanreiSnackbarResult.ActionPerformed -> unarchive()
                is TanreiSnackbarResult.Dismissed -> Unit
            }
        }
    })
    // El último del Box: se dibuja por encima del contenido y queda el último en el orden del foco.
    TanreiSnackbarHost(snackbars, Modifier.fillMaxSize())
}
import 'package:tanrei/tanrei.dart';

// Como ScaffoldMessenger. Ponlo alrededor de la página, dentro de su ruta, para que un diálogo abierto encima lo cubra.
TanreiSnackbarMessenger(child: page);

Future<void> archive(BuildContext context) async {
  await archiveConversation();
  final TanreiSnackbarController snackbar = TanreiSnackbarMessenger.of(context).show(
    const TanreiSnackbar(message: 'Conversación archivada', actionLabel: 'Deshacer'),
  );
  // Se completa con action, close, escape, timeout o host.
  if (await snackbar.closed == TanreiSnackbarClosedReason.action) {
    await restoreConversation();
  }
}
import { useSnackbar } from '@tanrei/react-native';

// El anfitrión vive en la capa de superposición de TanreiProvider: pon el proveedor en la raíz de tu aplicación.
const snackbar = useSnackbar();

async function archive() {
  await archiveConversation();
  const { result } = await snackbar.show({ message: 'Conversación archivada', actionLabel: 'Deshacer' });
  if (result === 'action') await restoreConversation();
}

Especificaciones

Un mensaje que ocupa varias líneas y una acción en su propia fila

Anatomía

Anatomía

Dibujado sobre el fixture message, tal como lo dibuja el paquete web.
Parte Descripción
1 container The bar that holds the text and the controls, raised above the content of its host. Its color is its form's: a surface of the scheme (the default form, or a faint tint of a status) or, drawn inverse, the opposite scheme's surface or, in a status form, the bar the other theme draws for that status: deep in a light scheme, pale in a dark one.
2 outline · opcional The edge of a status form: a hairline in the status's color, at the edge's opacity, around the bar where the ring of its elevation is. The default form and the inverse form draw none and keep that ring alone.
3 icon · opcional The status glyph from the system's icon set, before the text: info, warning, error or check_circle. Drawn only in a status form, a little softer than the text (in the status's own color on a surface and, on an inverse bar, in the status color of the other theme, at the glyph's opacity), and hidden from assistive technology, which hears statusLabel instead.
4 title · opcional A few words that name what happened, above the message. Up to three lines while collapsed.
5 supporting-text The message: what happened, or with a title the description, which is then drawn a little quieter than the title. Up to three lines while collapsed.
6 action · opcional One control that undoes or follows up on what happened, drawn as a tonal button with the snackbar's own tokens, as tall as the small Buttons beside it: the color of its own bar with a tonal layer of its label's color over it, so that it stands one quiet step off the bar, the same step in every form.
7 expand · opcional An icon-only Button of the small size that shows the whole title and message, and hides them again: the glyph expand_more while collapsed and expand_less while expanded. Drawn only while the text is longer than its collapsed limit, and drawn as the close button is (SNK-34).
8 close · opcional An icon-only Button of the small size showing the icon set's close glyph, which closes the snackbar. The snackbar places it, chooses its variant (comp.snackbar.close-button.variant: tonal in the default system) and gives it its form's tone (BTN-45): the glyph in the bar's message color and, where the variant draws a container, a circle of that color made translucent. Everything else it reads from Button's own tokens.
9 focus-ring · opcional Gap-then-ring indicator shown for keyboard focus of the action, or of the text while it scrolls, in the color its form gives it so that it shows on that form's bar. The expand and close buttons draw their own, in the same color (SNK-34).

Medidas

Medidas

Longitud Token Valor (px)
container padding-inline-start tanrei.comp.snackbar.container.padding-inline-start 16
container padding-inline-end tanrei.comp.snackbar.container.padding-inline-end 16
Dibujado sobre el fixture message, tal como lo dibuja el paquete web.

Propiedades

Propiedad Tipo Valor predeterminado Descripción
message string "" What happened; with a title, the description. Required. Plain text: the whole message is announced, even when a collapsed snackbar cuts it.
title string "" A few words above the message that name what happened ("Message not sent"). Empty draws the message alone.
action string "" The label of the one action ("Undo", "View"), drawn as a tonal button that sits one quiet step off the bar, the same step in every form. Empty draws no action.
status default | info | warning | error | success "default" The form of the snackbar. Default is the neutral bar with no glyph; info, warning, error and success draw the bar as a quiet tint of that status (pale on the scheme's surface or, drawn inverse, the bar the other theme draws for that status, with that theme's text, glyph and edge colors), with an edge in the status's color and the status's glyph before the text, and warning and error are announced assertively.
statusLabel string "" The status in words, in the product's language ("Error"), announced before the title and the message so that the status never rests on color and glyph alone. Required while status is not default.
inverse boolean null Whether this snackbar is drawn inverse: in the opposite scheme's colors (a dark bar in a light scheme), so that it stands apart from whatever it lands on. False draws it on a surface of the scheme. Null, the default, takes comp.snackbar.container.inverse, the system's choice, which is off in the default system. It changes colors only (SNK-30).
closable boolean false Draws a close button, for a message that stays until the person closes it or for one they may want gone sooner.
closeLabel string "" The close button's accessible name, in the product's language ("Close"). Required while closable is true.
expanded boolean false Whether the whole title and message show. The person toggles it with the expand button (SNK-24); it has no effect while the text fits within its collapsed limits.
expandLabel string "" The expand button's accessible name, in the product's language ("Show full message"). It stays the same while expanded; the button's expanded state says which way it acts. Required whenever the text can be longer than its collapsed limit.
duration auto | short | long | indefinite "auto" How long the snackbar stays by itself. Auto is short without an action and indefinite with one (WCAG 2.2.1: a person must not be timed out of an action). Short and long close after the snackbar's timeout tokens; indefinite stays until it is closed.
placement bottom | top-end "bottom" Where the host places the snackbar in its area. Bottom, the default, is the bottom edge, centred (SNK-13). Top-end is the top edge at the end side: the top right in a left-to-right layout and the top left in a right-to-left one, and across the top of a compact window (SNK-35). A host may be given one placement for all the snackbars it shows; a snackbar that names its own keeps it. It changes where the snackbar stands and the side it enters from (SNK-36, SNK-37), and nothing else: not its size, its form, its order in the queue, its place in the focus order or its announcement.

Eventos

Evento Descripción
action The action was activated. The snackbar closes.
dismiss The snackbar closed without its action; carries the reason: close (the close button), escape, timeout, or host (the product closed it or cleared the queue).
toggle The person expanded or collapsed the text with the expand button; carries the new expanded value. Not emitted when the product sets expanded.

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
SNK-1 WHEN the user activates the action by pointer, touch, Enter or Space THE snackbar SHALL emit action exactly once and close; WHEN the user activates the close button the same way THE snackbar SHALL emit dismiss with the reason close exactly once and close.
SNK-2 WHILE the action is hovered, keyboard-focused or pressed THE snackbar SHALL render the action's container, content color and opacity from the component tokens of the highest-precedence active state of the action, in the snackbar's form (SNK-21, SNK-30), with precedence pressed over focused over hovered; focus gained by pointer or touch SHALL NOT select the focused state. The expand and close buttons answer their states as any Button does (SNK-34).
SNK-3 WHEN the action receives keyboard focus THE snackbar SHALL show the focus ring around it without animation; focus gained by pointer or touch SHALL NOT show it. THE snackbar SHALL draw the outer stroke of that indicator, of the indicator inside the text while it scrolls and has keyboard focus (SNK-25) and, through the tone it gives them (SNK-34), of the indicators of the expand and close buttons, in its form's focus-ring color: comp.snackbar.focus-ring.color in the default form, and the token of that name under the form's prefix in every other (comp.snackbar.info.focus-ring.color, comp.snackbar.inverse.focus-ring.color, comp.snackbar.inverse-info.focus-ring.color, and warning's, error's and success's of the same names), never the system's focus-ring color role read directly. The widths and the offset SHALL stay the system's (sys.focus.outer-width, sys.focus.inner-width, sys.focus.offset), as SHALL the color of an inner stroke where the system draws one; under the glow focus style (SNK-7) the form's color SHALL be the halo's outer color.
SNK-4 WHERE the visual size of the action is below the minimum target THE snackbar SHALL extend the action's hit area on both axes to sys.target.touch for touch input and sys.target.pointer for fine pointers, without changing its visual size; a platform that cannot tell the input type SHALL use sys.target.touch.
SNK-5 WHEN the action is pressed by pointer, touch, Enter or Space THE snackbar SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner.
SNK-6 WHILE the action is pressed THE snackbar SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container of the action at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole action and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; content color, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.snackbar.motion.feedback-duration with comp.snackbar.motion.state-easing, fades over comp.snackbar.motion.state-duration with comp.snackbar.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced.
SNK-7 THE snackbar SHALL ease its container corners and the action's corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0) and show its keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README.
SNK-8 WHILE duration is auto THE snackbar SHALL behave as short when action is empty and as indefinite when action is set. WHILE duration is short or long THE snackbar SHALL close by itself once it has been shown for comp.snackbar.timeout.short or comp.snackbar.timeout.long, and emit dismiss with the reason timeout; WHERE the platform recommends a longer time for the person's accessibility settings (Android's accessibility timeout) it SHALL use that time, and WHERE the platform reports that a screen reader is running a snackbar with an action SHALL NOT close by itself. WHILE duration is indefinite THE snackbar SHALL NOT close by itself.
SNK-9 WHILE the pointer is over the snackbar, focus is inside it, it is expanded, the app's window is hidden or in the background, or a Tanrei modal dialog covers its host THE snackbar SHALL pause its timeout, and WHEN none of these holds any longer SHALL start the timeout again from its whole length.
SNK-10 WHEN a snackbar is shown THE snackbar SHALL have assistive technology announce it once: statusLabel first when status is not default, then the title when it has one, then the whole message (never only the part a collapsed snackbar shows), then the action's label when it has one. It SHALL announce politely (after what is being read) when status is default, info or success, and assertively (interrupting what is being read) when status is warning or error, and SHALL NOT move keyboard or screen-reader focus.
SNK-11 THE snackbar's controls SHALL be reachable in the focus order at the place its host has in that order, in this order whatever row each is drawn on: the text while it scrolls (SNK-25), the action, the expand button, the close button; WHEN the user presses Escape while focus is inside the snackbar THE snackbar SHALL emit dismiss with the reason escape and close; WHEN a snackbar closes while focus is inside it, focus SHALL return to the element that had it before focus entered the snackbar or, where that element no longer exists, to the platform's default.
SNK-12 THE host SHALL show one snackbar at a time, in the order they were requested: WHEN a snackbar is requested while another is showing or closing it SHALL wait until the other has closed, and WHILE a Tanrei modal dialog covers the host a snackbar not yet shown SHALL wait until the dialog closes. Each request SHALL resolve once its snackbar has closed, with action or with dismiss and its reason. WHEN the product closes the showing snackbar THE host SHALL close it and resolve it with dismiss and the reason host, and the next waiting one SHALL then show; WHEN the product clears the queue THE host SHALL also drop every waiting one and resolve each with dismiss and the reason host.
SNK-13 WHILE placement is bottom THE host SHALL place the snackbar at the bottom of its area, centred, comp.snackbar.container.margin above the bottom edge and at least comp.snackbar.container.margin from the side edges, inside the safe area and above the on-screen keyboard; at either placement it SHALL draw the snackbar above its area's content and below a Tanrei modal dialog and its scrim.
SNK-14 THE snackbar SHALL be at least comp.snackbar.container.min-height tall and as wide as its content between comp.snackbar.container.min-width and comp.snackbar.container.max-width, but never wider than its host less comp.snackbar.container.margin on each side. It SHALL draw comp.snackbar.container.color, or its form's container color (SNK-21, SNK-30), with comp.snackbar.container.elevation and comp.snackbar.container.shape corners, and pad its content by comp.snackbar.container.padding-inline-start before the status glyph or, without one, before the text, by comp.snackbar.container.padding-block below the text and by at least as much above it, where SNK-29 places the first line, and after the text by comp.snackbar.container.padding-inline-end when there is no control or by comp.snackbar.container.padding-inline-end-with-controls after the last control. WHILE the action stands on its own row (SNK-16) and no control follows the text on its row, the text SHALL end comp.snackbar.container.padding-inline-end from the end edge, as in a snackbar without controls, and padding-inline-end-with-controls SHALL be the action row's alone.
SNK-15 THE snackbar SHALL draw the message in comp.snackbar.supporting-text.typescale and comp.snackbar.supporting-text.color, or its form's message color (SNK-21, SNK-30), at the opacity SNK-32 gives a message under a title, followed comp.snackbar.container.gap after the text (the title and the message) by the action, the expand button and the close button, in that order, comp.snackbar.controls.gap apart and centred on the text's first line (SNK-29). The action SHALL be drawn as a tonal button, in its form's action colors: a container of comp.snackbar.action.container.color at least comp.snackbar.controls.height tall (the height of a small Button, so that the action stands as tall as the expand and close buttons in its row), the tonal layer over it (SNK-33), and comp.snackbar.controls.padding-inline around its label in comp.snackbar.controls.label.typescale and comp.snackbar.action.content.color, on comp.snackbar.controls.shape corners. The expand and close buttons SHALL be drawn as SNK-34 says.
SNK-16 WHEN the text (the title and the message) would need more than two lines beside the controls, or the action's label would itself wrap, THE snackbar SHALL move the action onto its own row below the text, comp.snackbar.container.gap below it and aligned to the end, with comp.snackbar.container.padding-inline-end-with-controls between that row and the bar's bottom edge, while the expand and close buttons stay at the end of the first row; the text SHALL wrap, and is cut only as SNK-23 says, and the action's label SHALL never wrap or be truncated.
SNK-17 WHEN a snackbar is shown THE snackbar SHALL rise into place from below the bottom edge of its host by its own height plus its margin while fading in (WHILE placement is bottom; at top-end it descends instead, SNK-36), over comp.snackbar.motion.enter-duration with comp.snackbar.motion.enter-easing; WHEN it closes it SHALL fade out in place over comp.snackbar.motion.exit-duration with comp.snackbar.motion.exit-easing, and the host SHALL show the next one only after that. WHERE motion is reduced it SHALL fade in and out without moving, or appear and disappear at once on a platform whose reduced-motion setting removes every animation (Android's).
SNK-18 WHEN the layout direction is right-to-left THE snackbar SHALL mirror its layout (the status glyph and the text at the right, the controls at the left) without mirroring any glyph, and SHALL grow a ripple from the point of contact as in left-to-right.
SNK-19 WHILE a snackbar is drawn outside a host (a snapshot harness, a documentation page) THE snackbar SHALL draw in place at its resting position, centred across the width it is given as SNK-13 centres it in a host (or, WHILE placement is top-end, at the end of that width as SNK-35 places it, and across the whole of it where that width is narrower than comp.snackbar.breakpoint.medium) and at most as tall as the height it is given, the width and the height it is given standing for the host's area in SNK-25 and SNK-35; it SHALL NOT time out, queue, animate its entrance or announce itself, and SHALL still emit action, dismiss and toggle.
SNK-20 WHILE message is empty THE snackbar SHALL still render and in debug builds report the empty message; WHILE closable is true and closeLabel is empty it SHALL still render the close button and in debug builds report that the button has no accessible name; WHILE status is not default and statusLabel is empty it SHALL still render the status form and in debug builds report that the status is not given in words; WHILE the expand button is drawn and expandLabel is empty it SHALL still render it and in debug builds report that it has no accessible name; WHEN duration is short or long and action is set it SHALL, in debug builds, remind the product that a timed action must also be offered elsewhere.
SNK-21 WHILE status is info, warning, error or success THE snackbar SHALL draw that status form: the bar, the title, the message and the status glyph in the status's container, title, supporting-text and icon colors, and every state of the action from the parts prefixed with the status, and give the expand and close buttons the status's tone (SNK-34). For info, while the snackbar is not drawn inverse (SNK-30), these are comp.snackbar.info.container.color, comp.snackbar.info.title.color, comp.snackbar.info.supporting-text.color, comp.snackbar.info.icon.color, comp.snackbar.info.outline.color for its edge (SNK-31), comp.snackbar.action.info.container.color and comp.snackbar.action.info.content.color; warning, error and success read their own tokens of the same names, and a status form drawn inverse reads the tokens SNK-30 names. Before the text it SHALL draw the status's glyph from the system's icon set (info for info, warning for warning, error for error, check_circle for success) at comp.snackbar.icon.size, in its form's icon color drawn at comp.snackbar.icon.opacity (an opacity of the glyph alone, which fades nothing else), comp.snackbar.icon.gap before the text and centred on the text's first line (SNK-29), with the family and fill of an unselected icon, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, never mirrored. The glyph so drawn SHALL keep 3:1 against its bar in every scheme of the default system. The glyph SHALL be hidden from assistive technology, and statusLabel SHALL be exposed as text before the title and the message. WHILE status is default THE snackbar SHALL draw no glyph and read the unprefixed tokens, or drawn inverse the tokens prefixed with inverse (SNK-30).
SNK-22 WHILE title is not empty THE snackbar SHALL draw it above the message in comp.snackbar.title.typescale and comp.snackbar.title.color, or its form's title color (SNK-21, SNK-30), with comp.snackbar.title.gap between the title and the message; WHILE title is empty it SHALL draw the message alone. THE snackbar SHALL set the title's letter-spacing 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.
SNK-23 WHILE expanded is false THE snackbar SHALL show at most comp.snackbar.title.max-lines lines of the title and at most comp.snackbar.supporting-text.max-lines lines of the message, each ending with an ellipsis where it is cut, at every text size, and the whole of both SHALL still reach assistive technology. WHILE the title or the message is longer than its collapsed limit THE snackbar SHALL draw the expand button, holding expand_more while collapsed and expand_less while expanded; WHILE both fit within their limits it SHALL NOT draw the expand button, and expanded SHALL have no effect. WHILE expanded is true THE snackbar SHALL show the whole title and message.
SNK-24 WHEN the user activates the expand button by pointer, touch, Enter or Space THE snackbar SHALL toggle expanded, emit toggle with the new value exactly once, keep focus on the expand button and stay open; the bar SHALL grow to its expanded height or shrink back over comp.snackbar.motion.expand-duration with comp.snackbar.motion.expand-easing, keeping its bottom edge in place WHILE placement is bottom and its top edge at top-end (SNK-37), and change at once where motion is reduced. The expand button SHALL expose to assistive technology whether the text is expanded and which text it shows and hides, and SHALL keep expandLabel as its name in both states. WHEN the product sets expanded THE snackbar SHALL change the same way without emitting toggle.
SNK-25 WHILE the snackbar is expanded and its whole content would make it taller than its host's area allows (the area's height less comp.snackbar.container.margin above and below, inside the safe area and above the on-screen keyboard) THE snackbar SHALL take that height and scroll its text inside the bar, keeping the status glyph, the controls and an action on its own row in place; WHILE the text scrolls it SHALL be reachable by keyboard (a focus stop, scrolled by the arrow keys, Page Up and Page Down), named by the title when there is one, and scrolled by wheel, trackpad and touch.
SNK-26 WHILE the system's icon set cannot yet draw a glyph of the snackbar (its font is still loading) — the status glyph, or the glyph it gives the expand or the close button — THE snackbar SHALL draw nothing in that glyph's place, never the glyph's name as text, SHALL keep the glyph's box, and SHALL draw the glyph once the set can; statusLabel, expandLabel and closeLabel SHALL still reach assistive technology.
SNK-27 THE snackbar 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 snackbar is shown THE snackbar SHALL draw itself for the new direction at once, without a motion of its own, keeping its open state, the time left before it closes and its focus.
SNK-28 THE snackbar SHALL lay out its title, its message and its action's label 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 snackbar 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 message cut by a line limit that does not fit (SNK-23) 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.
SNK-29 THE snackbar SHALL align its content to the top of the bar. It SHALL centre the first line of the text (the title's, or the message's without a title) half of comp.snackbar.container.min-height below the bar's top edge, or lower where comp.snackbar.container.padding-block plus half that line's height is more (enlarged text), and SHALL centre the status glyph and every control of the first row (the action while it is beside the text, the expand button and the close button) on that line; every further line of the text follows below it, an action on its own row (SNK-16) follows the text, and any height the bar has beyond its content SHALL lie below the content, never above it. WHEN the bar expands or collapses (SNK-24), and WHEN its text is cut or shown whole (SNK-23), the status glyph, the first line of the title and of the message, and every control of the first row SHALL keep their distance from the bar's top edge, during the motion and after it; an action on its own row SHALL keep its distance from the bar's bottom edge.
SNK-30 THE snackbar SHALL be drawn inverse WHILE inverse is true, or WHILE inverse is null and comp.snackbar.container.inverse is on; otherwise (inverse false, or null where that choice is off) it SHALL be drawn on a surface of the scheme, from the unprefixed tokens or its status form's (SNK-21). WHILE it is drawn inverse and status is default THE snackbar SHALL draw the bar, the title and the message in comp.snackbar.inverse.container.color, comp.snackbar.inverse.title.color and comp.snackbar.inverse.supporting-text.color, and every state of the action from the parts prefixed with inverse (comp.snackbar.action.inverse.container.color and comp.snackbar.action.inverse.content.color), and give the expand and close buttons that form's tone (SNK-34). WHILE it is drawn inverse and status is info, warning, error or success it SHALL draw that status's inverse form the same way, from the parts prefixed with inverse- and the status: for info comp.snackbar.inverse-info.container.color, comp.snackbar.inverse-info.title.color, comp.snackbar.inverse-info.supporting-text.color, comp.snackbar.inverse-info.icon.color, comp.snackbar.inverse-info.outline.color for its edge (SNK-31), comp.snackbar.action.inverse-info.container.color and comp.snackbar.action.inverse-info.content.color, and for warning, error and success their own tokens of the same names. Under the default system each color of a status's inverse form SHALL be the color the same part of that status's form not drawn inverse has in the scheme of the other theme at the same contrast level (light for dark, light-medium for dark-medium, light-high for dark-high, and each the other way): the bar, the title, the message, the glyph, the edge, the focus indicator, every state of the action and the tone of the expand and close buttons, so that the inverse form of a status in one theme and its form on a surface in the other differ only in what lies around the bar. Being drawn inverse SHALL change colors only: the bar's elevation, corners, sizes and layout, the glyphs, the width and the opacity of a status form's edge, the opacities of the glyph, of a message under a title and of the action's tonal layer, the motion, the timing, the announcement and the keyboard behaviour SHALL be those of the same snackbar not drawn inverse. WHEN inverse or the system's choice changes while the snackbar is shown THE snackbar SHALL draw the other form at once, keeping its open state, the time left before it closes and its focus.
SNK-31 WHILE status is info, warning, error or success THE snackbar SHALL draw its form's edge: a line comp.snackbar.outline.width wide around the bar, outside the bar's bounds and following its corners, where the ring of comp.snackbar.container.elevation lies (the layer of that elevation with no offset, no blur and a positive spread), over that ring and above the elevation's shadows, in the form's outline color drawn at comp.snackbar.outline.opacity: comp.snackbar.info.outline.color for info, comp.snackbar.inverse-info.outline.color for info drawn inverse (SNK-30), and warning's, error's and success's tokens of the same names. The edge SHALL NOT change the bar's size or the place of anything inside or around it, and the focus indicator of a control SHALL be drawn above it. WHILE status is default THE snackbar SHALL draw no edge of its own, drawn inverse or not: the ring of its elevation shows alone, as on every raised surface. WHERE comp.snackbar.outline.opacity is 0 a status form SHALL draw no edge either.
SNK-32 WHILE title is not empty THE snackbar SHALL draw the message at comp.snackbar.supporting-text.under-title.opacity: an opacity of the message's text alone, applied to its form's message color (SNK-15), in every form, collapsed and expanded. WHILE title is empty it SHALL draw the message whole, and it SHALL draw the title whole in every form. The message so drawn SHALL keep 4.5:1 against its bar in every scheme of the default system, and 7:1 in its high-contrast schemes; what assistive technology reads SHALL NOT change with it.
SNK-33 THE snackbar SHALL draw the action's tonal layer in every form and in every state of the action: the action's content color of that form and state, at comp.snackbar.action.tonal-layer.opacity, filling the action's container to its corners, above the container color of that state (SNK-2) and above a ripple that grows on it (SNK-6), and under the label. The layer is the action's alone, SHALL NOT take a press or change the action's size, and SHALL NOT be drawn WHERE comp.snackbar.action.tonal-layer.opacity is 0, where the action is its container alone. The label SHALL keep 4.5:1 against the action as drawn (the container color of the state with the layer over it) in every form, state and scheme of the default system, and 7:1 in its high-contrast schemes.
SNK-34 WHILE closable is true, and WHILE the expand button is drawn (SNK-23), THE snackbar SHALL draw that button, in the place SNK-15, SNK-16 and SNK-29 give it, as an icon-only Button of the small size showing a glyph of the system's icon set (close; expand_more or expand_less, SNK-23) and named by closeLabel or expandLabel, in the variant comp.snackbar.close-button.variant names and in the tone of the snackbar's form (BTN-45): the form's message color — comp.snackbar.supporting-text.color in the default form, and the token of that name under the form's prefix in every other (SNK-21, SNK-30) — with the form's focus-ring color (SNK-3) for its focus indicator, both given through the channel a Button reads from the component that places it, and otherwise unrestyled: it reads Button's own tokens for its size, glyph size, corners and state opacities, answers hover, focus and press as any Button does, and keeps its own minimum target (BTN-5). WHEN the snackbar's form changes while it is shown THE snackbar SHALL give the buttons the new form's tone with the new form's colors (SNK-30). THE snackbar SHALL draw no close or expand mark of its own (no path, shape or character of its own), and the expand button SHALL expose to assistive technology whether the text is expanded and which text it shows and hides (SNK-24).
SNK-35 WHILE placement is top-end THE host SHALL place the snackbar at the top of its area, at its end side (the right in a left-to-right layout and the left in a right-to-left one, taken from where the host is used as SNK-27 says), comp.snackbar.container.margin below the top edge and comp.snackbar.container.margin from the end edge, inside the safe area and below what the frame keeps over the top of the area (a sticky header's present height, APS-17), so that it never covers a top app bar; WHILE the area is narrower than comp.snackbar.breakpoint.medium (a compact window) it SHALL draw the snackbar across the top of the area instead, as wide as the area less comp.snackbar.container.margin on each side, within comp.snackbar.container.max-width. WHEN the product asks for a snackbar without a placement THE host SHALL give it the placement the host itself is given, and bottom where it is given none. The placement SHALL NOT change the snackbar's layer (SNK-13), its other size bounds (SNK-14), its place in the focus order (SNK-11) or its announcement (SNK-10), and the host SHALL still show one snackbar at a time, in order (SNK-12): at the top as at the bottom, a snackbar asked for while another shows waits for it to close, and no two are stacked.
SNK-36 WHILE placement is top-end, WHEN a snackbar is shown THE snackbar SHALL descend into place from above the top edge of its host by its own height plus its margin while fading in, over comp.snackbar.motion.enter-duration with comp.snackbar.motion.enter-easing, as SNK-17 rises at the bottom; WHEN it closes it SHALL fade out in place as SNK-17 says, and WHERE motion is reduced it SHALL fade in and out without moving, or appear and disappear at once where the platform removes every animation.
SNK-37 WHILE placement is top-end, WHEN the bar expands or collapses (SNK-24) THE snackbar SHALL grow downward and shrink back with its top edge in place, so that, its content being aligned to the top (SNK-29), nothing of its first row moves on the screen during the motion or after it; WHILE it is expanded it SHALL be at most as tall as SNK-25 allows, the area's height being measured from below what the frame keeps over its top (SNK-35).

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-snackbar TanreiSnackbar TanreiSnackbar TanreiSnackbar Snackbar
message · Propiedad message message message message message
title · Propiedad headline title title title title
action · Propiedad action actionLabel actionLabel actionLabel actionLabel
status · Propiedad status status status status status
statusLabel · Propiedad statusLabel statusLabel statusLabel statusLabel statusLabel
inverse · Propiedad inverse inverse inverse inverse inverse
closable · Propiedad closable withCloseButton withDismissAction showCloseIcon closable
closeLabel · Propiedad closeLabel closeLabel closeLabel closeIconLabel closeLabel
expanded · Propiedad expanded isExpanded expanded expanded expanded
expandLabel · Propiedad expandLabel expandLabel expandLabel expandLabel expandLabel
duration · Propiedad duration duration duration duration duration
placement · Propiedad placement placement placement placement placement
action · Evento action TanreiSnackbarResult.action TanreiSnackbarResult.ActionPerformed TanreiSnackbarClosedReason.action onAction
dismiss · Evento dismiss TanreiSnackbarResult.dismissed TanreiSnackbarResult.Dismissed TanreiSnackbarClosedReason onDismiss
toggle · Evento expandedchange onExpandedChange onExpandedChange onExpandedChanged onExpandedChange
Notas title is the headline property and attribute, because HTML's global title attribute would show a tooltip over the whole bar (as the app bar's). closeLabel, statusLabel and expandLabel are the close-label, status-label and expand-label attributes. inverse is a property that is true, false or null (the default); the inverse attribute sets it: absent is null, present (empty or true) is true, and inverse="false" is false, the one way to refuse a system whose choice is on. While it is null the snackbar reads --tanrei-comp-snackbar-container-inverse from the cascade, which carries the choice's name (SNK-30). The opacities of SNK-21, SNK-31, SNK-32 and SNK-33 are applied to the color of the part they name (a mix of that color with transparent), never as an element's opacity, so nothing else fades with it; a status form's edge is a shadow layer of its own before the elevation's, and the tonal layer lies inside the action, under its label. The focus indicator's color is the form's focus-ring-color custom property, handed to the shared focus primitive (SNK-3). The expand and close buttons are <tanrei-button size="small"> elements in the snackbar's shadow root, given the variant --tanrei-comp-snackbar-close-button-variant names and the form's tone through the Button's internal channel (SNK-34); the expand button's expanded state and the text it controls are written on the Button's own native button (aria-expanded, and ariaControlsElements, since an id cannot be named across the Button's shadow root). dismiss is a CustomEvent whose detail.reason is the reason. toggle is the expandedchange CustomEvent, whose detail.expanded is the new value, because a popover element already fires a native toggle when it is shown and hidden. The host (<tanrei-snackbar-host>) queues and places snackbars; show(options) takes title, status, statusLabel, inverse and expandLabel as well; see the accessibility notes. placement is the placement attribute of <tanrei-snackbar> and of <tanrei-snackbar-host>: the host's is the placement of each snackbar whose show() options name none (SNK-35). What the frame keeps over the top of the area is --tanrei-app-shell-scroll-offset on the document's root, which <tanrei-app-shell> sets to its sticky header's height (APS-17) and a product's own frame may set; the safe area is env(safe-area-inset-*). A compact window is one narrower than --tanrei-comp-snackbar-breakpoint-medium, read by the stylesheet itself, with no listener. Snapshot harness: each fixture is a <tanrei-snackbar> rendered outside a host (SNK-19), on a 400 px wide stage; expanded-scrolls on a stage 400 × 240, and top-end and top-end-rtl on a stage 720 wide, wider than a compact window. Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. A host is a @Observable TanreiSnackbarHost attached with .tanreiSnackbarHost(_:) on the view whose bottom edge it uses; await host.show(message:actionLabel:withCloseButton:closeLabel:duration:) returns a TanreiSnackbarResult (.action, or .dismissed(reason)) once the snackbar has closed. It is drawn in an overlay of that view, not in a sheet, which would be modal. Snapshot harness: TanreiSnackbar rendered in place (SNK-19) in a 400-point frame. inverse is a Bool?, nil by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. Shaped like Material's snackbar API: TanreiSnackbarHost(hostState) is placed in the layout (for example a scaffold's snackbar slot), and hostState.showSnackbar(message, actionLabel, withDismissAction, closeLabel, duration) suspends until the snackbar has closed and returns the result; cancelling the coroutine closes it with the reason host. The recommended timeout is AccessibilityManager.calculateRecommendedTimeoutMillis. Snapshot harness: TanreiSnackbar(message = …) rendered in place (SNK-19) in a 400 dp wide box. inverse is a Boolean?, null by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. Shaped like Flutter's ScaffoldMessenger: a TanreiSnackbarMessenger placed around the page, inside its route, hosts the queue (so a Tanrei dialog's route covers it and SNK-12's wait applies), and TanreiSnackbarMessenger.of(context).show(TanreiSnackbar(...)) returns a controller whose closed future completes with a TanreiSnackbarClosedReason (action, close, escape, timeout, host). showCloseIcon is Flutter's own name for the close button. A running screen reader is MediaQuery.accessibleNavigation (as Flutter's own SnackBar reads it); Android's recommended timeout needs a platform channel, since Flutter does not expose it. Snapshot harness: a golden of TanreiSnackbar rendered in place (SNK-19) in a 400-wide surface. inverse is a bool?, null by default. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20). Lagging: ships an earlier form of the snackbar: always an inverse bar, with a text action, no status forms, no title, no expansion and no inverse. TanreiProvider renders the host in its root overlay layer, not in a Modal (a Modal is modal and takes focus); useSnackbar().show({ message, actionLabel, closable, closeLabel, duration }) returns a promise of the result. A Snackbar element rendered directly is drawn in place (SNK-19). Snapshot harness: Snackbar rendered in place in a 400-wide view. inverse is boolean | null | undefined; both null and undefined take the system's choice. Not yet: the top-end placement (SNK-35, SNK-36, SNK-37); the expand and close buttons as small Buttons in the form's tone (SNK-34); the title's letter-spacing by the script of its text (SNK-22, PRS-20).

Tokens

Token Alias de Valor resuelto (claro)
--tanrei-comp-snackbar-action-container-color comp.snackbar.container.color #ffffff
--tanrei-comp-snackbar-action-content-color comp.snackbar.supporting-text.color #1b1b1b
--tanrei-comp-snackbar-action-error-container-color comp.snackbar.error.container.color #ffedeb
--tanrei-comp-snackbar-action-error-content-color comp.snackbar.error.supporting-text.color #3a211f
--tanrei-comp-snackbar-action-error-state-layer-color comp.snackbar.action.error.content.color #3a211f
--tanrei-comp-snackbar-action-focused-container-color — #e8e8e8
--tanrei-comp-snackbar-action-focused-content-color — #1b1b1b
--tanrei-comp-snackbar-action-focused-error-container-color — #ebd9d7
--tanrei-comp-snackbar-action-focused-error-content-color — #3a211f
--tanrei-comp-snackbar-action-focused-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-focused-info-container-color — #d9dceb
--tanrei-comp-snackbar-action-focused-info-content-color — #212839
--tanrei-comp-snackbar-action-focused-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-focused-inverse-error-container-color — #4a312f
--tanrei-comp-snackbar-action-focused-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-focused-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-focused-inverse-info-container-color — #303748
--tanrei-comp-snackbar-action-focused-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-focused-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-focused-inverse-success-container-color — #2b3b2b
--tanrei-comp-snackbar-action-focused-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-focused-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-focused-inverse-warning-container-color — #47341f
--tanrei-comp-snackbar-action-focused-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-focused-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-focused-inverse-container-color — #343434
--tanrei-comp-snackbar-action-focused-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-focused-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-focused-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-focused-success-container-color — #cee2cc
--tanrei-comp-snackbar-action-focused-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-focused-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-focused-warning-container-color — #ebdacb
--tanrei-comp-snackbar-action-focused-warning-content-color — #362410
--tanrei-comp-snackbar-action-focused-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-hovered-container-color — #ededed
--tanrei-comp-snackbar-action-hovered-content-color — #1b1b1b
--tanrei-comp-snackbar-action-hovered-error-container-color — #efdddb
--tanrei-comp-snackbar-action-hovered-error-content-color — #3a211f
--tanrei-comp-snackbar-action-hovered-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-hovered-info-container-color — #dde0ef
--tanrei-comp-snackbar-action-hovered-info-content-color — #212839
--tanrei-comp-snackbar-action-hovered-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-hovered-inverse-error-container-color — #462d2b
--tanrei-comp-snackbar-action-hovered-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-hovered-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-hovered-inverse-info-container-color — #2c3344
--tanrei-comp-snackbar-action-hovered-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-hovered-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-hovered-inverse-success-container-color — #273727
--tanrei-comp-snackbar-action-hovered-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-hovered-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-hovered-inverse-warning-container-color — #42301b
--tanrei-comp-snackbar-action-hovered-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-hovered-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-hovered-inverse-container-color — #303030
--tanrei-comp-snackbar-action-hovered-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-hovered-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-hovered-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-hovered-success-container-color — #d2e6cf
--tanrei-comp-snackbar-action-hovered-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-hovered-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-hovered-warning-container-color — #efdecf
--tanrei-comp-snackbar-action-hovered-warning-content-color — #362410
--tanrei-comp-snackbar-action-hovered-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-info-container-color comp.snackbar.info.container.color #edf0ff
--tanrei-comp-snackbar-action-info-content-color comp.snackbar.info.supporting-text.color #212839
--tanrei-comp-snackbar-action-info-state-layer-color comp.snackbar.action.info.content.color #212839
--tanrei-comp-snackbar-action-inverse-error-container-color comp.snackbar.inverse-error.container.color #361d1b
--tanrei-comp-snackbar-action-inverse-error-content-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-action-inverse-error-state-layer-color comp.snackbar.action.inverse-error.content.color #ffe1df
--tanrei-comp-snackbar-action-inverse-info-container-color comp.snackbar.inverse-info.container.color #1c2334
--tanrei-comp-snackbar-action-inverse-info-content-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-action-inverse-info-state-layer-color comp.snackbar.action.inverse-info.content.color #e1e8ff
--tanrei-comp-snackbar-action-inverse-success-container-color comp.snackbar.inverse-success.container.color #172718
--tanrei-comp-snackbar-action-inverse-success-content-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-action-inverse-success-state-layer-color comp.snackbar.action.inverse-success.content.color #daeed6
--tanrei-comp-snackbar-action-inverse-warning-container-color comp.snackbar.inverse-warning.container.color #32200c
--tanrei-comp-snackbar-action-inverse-warning-content-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-action-inverse-warning-state-layer-color comp.snackbar.action.inverse-warning.content.color #ffe3cb
--tanrei-comp-snackbar-action-inverse-container-color comp.snackbar.inverse.container.color #1f1f1f
--tanrei-comp-snackbar-action-inverse-content-color comp.snackbar.inverse.supporting-text.color #f1f1f1
--tanrei-comp-snackbar-action-inverse-state-layer-color comp.snackbar.action.inverse.content.color #f1f1f1
--tanrei-comp-snackbar-action-pressed-container-color — #e8e8e8
--tanrei-comp-snackbar-action-pressed-content-color — #1b1b1b
--tanrei-comp-snackbar-action-pressed-error-container-color — #ebd9d7
--tanrei-comp-snackbar-action-pressed-error-content-color — #3a211f
--tanrei-comp-snackbar-action-pressed-error-state-layer-color — #3a211f
--tanrei-comp-snackbar-action-pressed-info-container-color — #d9dceb
--tanrei-comp-snackbar-action-pressed-info-content-color — #212839
--tanrei-comp-snackbar-action-pressed-info-state-layer-color — #212839
--tanrei-comp-snackbar-action-pressed-inverse-error-container-color — #4a312f
--tanrei-comp-snackbar-action-pressed-inverse-error-content-color — #ffe1df
--tanrei-comp-snackbar-action-pressed-inverse-error-state-layer-color — #ffe1df
--tanrei-comp-snackbar-action-pressed-inverse-info-container-color — #303748
--tanrei-comp-snackbar-action-pressed-inverse-info-content-color — #e1e8ff
--tanrei-comp-snackbar-action-pressed-inverse-info-state-layer-color — #e1e8ff
--tanrei-comp-snackbar-action-pressed-inverse-success-container-color — #2b3b2b
--tanrei-comp-snackbar-action-pressed-inverse-success-content-color — #daeed6
--tanrei-comp-snackbar-action-pressed-inverse-success-state-layer-color — #daeed6
--tanrei-comp-snackbar-action-pressed-inverse-warning-container-color — #47341f
--tanrei-comp-snackbar-action-pressed-inverse-warning-content-color — #ffe3cb
--tanrei-comp-snackbar-action-pressed-inverse-warning-state-layer-color — #ffe3cb
--tanrei-comp-snackbar-action-pressed-inverse-container-color — #343434
--tanrei-comp-snackbar-action-pressed-inverse-content-color — #f1f1f1
--tanrei-comp-snackbar-action-pressed-inverse-state-layer-color — #f1f1f1
--tanrei-comp-snackbar-action-pressed-state-layer-color — #1b1b1b
--tanrei-comp-snackbar-action-pressed-success-container-color — #cee2cc
--tanrei-comp-snackbar-action-pressed-success-content-color — #1b2c1c
--tanrei-comp-snackbar-action-pressed-success-state-layer-color — #1b2c1c
--tanrei-comp-snackbar-action-pressed-warning-container-color — #ebdacb
--tanrei-comp-snackbar-action-pressed-warning-content-color — #362410
--tanrei-comp-snackbar-action-pressed-warning-state-layer-color — #362410
--tanrei-comp-snackbar-action-state-layer-color comp.snackbar.action.content.color #1b1b1b
--tanrei-comp-snackbar-action-success-container-color comp.snackbar.success.container.color #e2f6df
--tanrei-comp-snackbar-action-success-content-color comp.snackbar.success.supporting-text.color #1b2c1c
--tanrei-comp-snackbar-action-success-state-layer-color comp.snackbar.action.success.content.color #1b2c1c
--tanrei-comp-snackbar-action-tonal-layer-opacity — 0.12
--tanrei-comp-snackbar-action-warning-container-color comp.snackbar.warning.container.color #ffeee0
--tanrei-comp-snackbar-action-warning-content-color comp.snackbar.warning.supporting-text.color #362410
--tanrei-comp-snackbar-action-warning-state-layer-color comp.snackbar.action.warning.content.color #362410
--tanrei-comp-snackbar-breakpoint-medium sys.breakpoint.medium 600px
--tanrei-comp-snackbar-close-button-variant — 1
--tanrei-comp-snackbar-container-color sys.color.surface-bright #ffffff
--tanrei-comp-snackbar-container-elevation sys.elevation.level3 0px 0px 0px 1px rgb(0 0 0 / 0.08), 0px 1px 1px 0px rgb(0 0 0 / 0.04), 0px 4px 8px -4px rgb(0 0 0 / 0.04), 0px 16px 24px -8px rgb(0 0 0 / 0.06)
--tanrei-comp-snackbar-container-gap sys.space.space100 8px
--tanrei-comp-snackbar-container-inverse — 0
--tanrei-comp-snackbar-container-margin sys.space.space200 16px
--tanrei-comp-snackbar-container-max-width — 560px
--tanrei-comp-snackbar-container-min-height — 48px
--tanrei-comp-snackbar-container-min-width — 288px
--tanrei-comp-snackbar-container-padding-block sys.space.space150 12px
--tanrei-comp-snackbar-container-padding-inline-end sys.space.space200 16px
--tanrei-comp-snackbar-container-padding-inline-end-with-controls sys.space.space100 8px
--tanrei-comp-snackbar-container-padding-inline-start sys.space.space200 16px
--tanrei-comp-snackbar-container-shape sys.shape.corner.medium 8px
--tanrei-comp-snackbar-controls-gap sys.space.space50 4px
--tanrei-comp-snackbar-controls-height comp.button.container.height.small 32px
--tanrei-comp-snackbar-controls-padding-inline sys.space.space175 14px
--tanrei-comp-snackbar-controls-shape sys.shape.corner.full 9999px
--tanrei-comp-snackbar-error-container-color sys.color.error-container #ffedeb
--tanrei-comp-snackbar-error-focus-ring-color sys.color.on-error-container #3a211f
--tanrei-comp-snackbar-error-icon-color sys.color.error #cd262f
--tanrei-comp-snackbar-error-outline-color sys.color.error #cd262f
--tanrei-comp-snackbar-error-supporting-text-color sys.color.on-error-container #3a211f
--tanrei-comp-snackbar-error-title-color comp.snackbar.error.supporting-text.color #3a211f
--tanrei-comp-snackbar-focus-ring-color sys.color.focus-ring #0070ac
--tanrei-comp-snackbar-focused-opacity — 1
--tanrei-comp-snackbar-hovered-opacity — 1
--tanrei-comp-snackbar-icon-gap sys.space.space150 12px
--tanrei-comp-snackbar-icon-opacity — 0.85
--tanrei-comp-snackbar-icon-size sys.icon.medium 24px
--tanrei-comp-snackbar-info-container-color sys.color.info-container #edf0ff
--tanrei-comp-snackbar-info-focus-ring-color sys.color.on-info-container #212839
--tanrei-comp-snackbar-info-icon-color sys.color.info #3066cb
--tanrei-comp-snackbar-info-outline-color sys.color.info #3066cb
--tanrei-comp-snackbar-info-supporting-text-color sys.color.on-info-container #212839
--tanrei-comp-snackbar-info-title-color comp.snackbar.info.supporting-text.color #212839
--tanrei-comp-snackbar-inverse-error-container-color sys.color.on-error-container #361d1b
--tanrei-comp-snackbar-inverse-error-focus-ring-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-inverse-error-icon-color comp.snackbar.inverse-error.supporting-text.color #ff928c
--tanrei-comp-snackbar-inverse-error-outline-color sys.color.error #ff928c
--tanrei-comp-snackbar-inverse-error-supporting-text-color sys.color.error-container #ffe1df
--tanrei-comp-snackbar-inverse-error-title-color comp.snackbar.inverse-error.supporting-text.color #ffe1df
--tanrei-comp-snackbar-inverse-info-container-color sys.color.on-info-container #1c2334
--tanrei-comp-snackbar-inverse-info-focus-ring-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-inverse-info-icon-color comp.snackbar.inverse-info.supporting-text.color #8eafff
--tanrei-comp-snackbar-inverse-info-outline-color sys.color.info #8eafff
--tanrei-comp-snackbar-inverse-info-supporting-text-color sys.color.info-container #e1e8ff
--tanrei-comp-snackbar-inverse-info-title-color comp.snackbar.inverse-info.supporting-text.color #e1e8ff
--tanrei-comp-snackbar-inverse-success-container-color sys.color.on-success-container #172718
--tanrei-comp-snackbar-inverse-success-focus-ring-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-inverse-success-icon-color comp.snackbar.inverse-success.supporting-text.color #62c572
--tanrei-comp-snackbar-inverse-success-outline-color sys.color.success #62c572
--tanrei-comp-snackbar-inverse-success-supporting-text-color sys.color.success-container #daeed6
--tanrei-comp-snackbar-inverse-success-title-color comp.snackbar.inverse-success.supporting-text.color #daeed6
--tanrei-comp-snackbar-inverse-warning-container-color sys.color.on-warning-container #32200c
--tanrei-comp-snackbar-inverse-warning-focus-ring-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-inverse-warning-icon-color comp.snackbar.inverse-warning.supporting-text.color #f39e3a
--tanrei-comp-snackbar-inverse-warning-outline-color sys.color.warning #f39e3a
--tanrei-comp-snackbar-inverse-warning-supporting-text-color sys.color.warning-container #ffe3cb
--tanrei-comp-snackbar-inverse-warning-title-color comp.snackbar.inverse-warning.supporting-text.color #ffe3cb
--tanrei-comp-snackbar-inverse-container-color sys.color.inverse-surface #1f1f1f
--tanrei-comp-snackbar-inverse-focus-ring-color sys.color.inverse-on-surface #f1f1f1
--tanrei-comp-snackbar-inverse-supporting-text-color sys.color.inverse-on-surface #f1f1f1
--tanrei-comp-snackbar-inverse-title-color comp.snackbar.inverse.supporting-text.color #f1f1f1
--tanrei-comp-snackbar-motion-enter-duration sys.motion.role.appear.toast.enter 350ms
--tanrei-comp-snackbar-motion-enter-easing sys.motion.easing.enter cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-motion-exit-duration sys.motion.role.appear.toast.exit 300ms
--tanrei-comp-snackbar-motion-exit-easing sys.motion.easing.exit cubic-bezier(0.3, 0, 1, 1)
--tanrei-comp-snackbar-motion-expand-duration sys.motion.role.resize.large 400ms
--tanrei-comp-snackbar-motion-expand-easing sys.motion.easing.spatial cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-motion-feedback-duration sys.motion.role.feedback 450ms
--tanrei-comp-snackbar-motion-state-duration sys.motion.role.state.default 250ms
--tanrei-comp-snackbar-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-snackbar-outline-opacity — 0.4
--tanrei-comp-snackbar-outline-width sys.border.hairline 1px
--tanrei-comp-snackbar-pressed-opacity — 1
--tanrei-comp-snackbar-success-container-color sys.color.success-container #e2f6df
--tanrei-comp-snackbar-success-focus-ring-color sys.color.on-success-container #1b2c1c
--tanrei-comp-snackbar-success-icon-color sys.color.success #077b32
--tanrei-comp-snackbar-success-outline-color sys.color.success #077b32
--tanrei-comp-snackbar-success-supporting-text-color sys.color.on-success-container #1b2c1c
--tanrei-comp-snackbar-success-title-color comp.snackbar.success.supporting-text.color #1b2c1c
--tanrei-comp-snackbar-supporting-text-color sys.color.on-surface #1b1b1b
--tanrei-comp-snackbar-supporting-text-max-lines — 3
--tanrei-comp-snackbar-supporting-text-under-title-opacity — 0.8
--tanrei-comp-snackbar-timeout-long — 10000ms
--tanrei-comp-snackbar-timeout-short — 4000ms
--tanrei-comp-snackbar-title-color comp.snackbar.supporting-text.color #1b1b1b
--tanrei-comp-snackbar-title-gap sys.space.space50 4px
--tanrei-comp-snackbar-title-max-lines — 3
--tanrei-comp-snackbar-warning-container-color sys.color.warning-container #ffeee0
--tanrei-comp-snackbar-warning-focus-ring-color sys.color.on-warning-container #362410
--tanrei-comp-snackbar-warning-icon-color sys.color.warning #9b5c00
--tanrei-comp-snackbar-warning-outline-color sys.color.warning #9b5c00
--tanrei-comp-snackbar-warning-supporting-text-color sys.color.on-warning-container #362410
--tanrei-comp-snackbar-warning-title-color comp.snackbar.warning.supporting-text.color #362410
--tanrei-comp-snackbar-controls-label-typescale sys.typescale.label 500 14px/1.4286
--tanrei-comp-snackbar-supporting-text-typescale sys.typescale.body 400 14px/1.5714
--tanrei-comp-snackbar-title-typescale sys.typescale.heading-6 500 14px/1.4286

Fixtures

Representaciones canónicas. Todas las plataformas capturan cada fixture con el mismo identificador para poder comparar los resultados.

Generado a partir de specs/snackbar.spec.json, tokens/comp/snackbar.tokens.json, design/tokens/

Pautas

Cuándo usarlo

Usa un snackbar para confirmar algo que la persona acaba de hacer, cuando terminó sin una pantalla propia: «Conversación archivada», «Enlace copiado», «Foto guardada». Ofrece como máximo una acción que lo deshaga o le dé continuidad.

Un snackbar informa; no pregunta. Una elección entre dos acciones, un error que bloquea el trabajo de la persona o cualquier cosa de la que deba darse por enterada van en un diálogo o junto a aquello de lo que tratan. La forma de error es para un fallo al que la persona puede volver, como «Mensaje no enviado» con Reintentar.

Los dos aparecen por encima de la página y hacen trabajos opuestos.

Aspecto Snackbar Diálogo
Qué hace Informa de algo que ya ha ocurrido. Pide una decisión, o que la persona se dé por enterada de algo, antes de que el trabajo continúe.
Foco Nunca se mueve. La persona sigue trabajando. Pasa al diálogo. La página que queda detrás no se puede usar.
Cuánto permanece Unos segundos, o hasta que se usa su acción o su botón de cierre. Hasta que la persona responde.
Acciones Una como máximo, y el mensaje está completo sin ella. Las respuestas a su pregunta.

Si las personas pueden ignorar el mensaje sin que nada vaya mal, es un snackbar. Si la aplicación no puede continuar sin una respuesta, es un diálogo. Un mensaje que pertenece a una parte de la pantalla y tiene que seguir a la vista, como lo que está mal en un campo, va en ese lugar, por ejemplo como texto de apoyo del campo.

Partes

Parte Se define con Notas
Barra inverse Una superficie elevada del esquema de forma predeterminada, o los colores del esquema opuesto; consulta Sobre una superficie o en inverso.
Glifo de estado status y statusLabel Opcional. Una forma de estado dibuja su glifo antes del texto; consulta Formas de estado.
Título title (headline en la web) Opcional. Un encabezado corto encima del mensaje, en un estilo más grueso del mismo tamaño que el mensaje. Sin él, el mensaje va solo.
Mensaje message Obligatorio. Texto sin formato, una o dos frases cortas, que se anuncia entero. Con un título, es la descripción y se dibuja algo más discreto que el título.
Acción action (la etiqueta) Opcional: «Deshacer», «Ver», «Reintentar». Se dibuja como un botón tonal: una cápsula a un paso discreto de su barra, con la etiqueta en el color del texto de la barra. El snackbar la dibuja con sus propios tokens, no como un Button, tan alta como los Button pequeños que tiene al lado. Pasa a su propia fila cuando el texto necesitaría más de dos líneas a su lado, contando juntas las líneas del título y las del mensaje, o cuando su etiqueta tendría que saltar de línea.
Botón de expandir expandLabel, expanded Un Button pequeño de solo icono, dibujado como el botón de cierre. Solo se dibuja mientras el título o el mensaje ocupan más de tres líneas. expandLabel es su nombre accesible, como «Mostrar el mensaje completo».
Botón de cierre closable y closeLabel Opcional. Un Button pequeño de solo icono. Para un mensaje que permanece hasta que se cierra, o uno que las personas pueden querer quitar antes. closeLabel es su nombre accesible, en el idioma de tu producto.

La acción, el botón de expandir y el botón de cierre se sitúan junto a la primera línea del texto, los tres tan altos como un Button pequeño.

Los botones de expandir y de cierre

Los botones de expandir y de cierre son Button pequeños de solo icono, con los glifos expand_more, expand_less y close del conjunto de iconos. Son tonales, como todos los botones de cierre de Tanrei, y toman su color de la barra: el glifo tiene el color del texto de la barra, sobre un círculo de ese mismo color vuelto translúcido. Así se leen como controles en cualquier forma, ya sea una superficie, el tinte de un estado o una barra en inverso, y nunca traen un color que la barra no tenga ya. El paso del cursor, el foco y la pulsación son los de un Button, sobre ese mismo color, y su anillo de foco es el color de foco de la propia barra.

Un producto puede dibujarlos como un glifo solo. Lo hace una vez, para todos los snackbars, en la capa de su sistema de diseño, dando a comp.snackbar.close-button.variant la variante text; los presets de Material y de Cupertino hacen exactamente eso, para conservar el glifo solo que tienen sus originales.

La acción

La acción es un botón tonal que se apoya en su barra. Su contenedor es el color de la propia barra con una capa tenue del color de la etiqueta por encima, de modo que queda al mismo paso discreto de la barra en todas las formas: sobre una superficie o en inverso, con estado o sin él. La etiqueta tiene el color del texto de la barra.

Es tonal porque suele ser un deshacer, y la persona que acaba de equivocarse tiene que ver de inmediato que hay un botón. Una etiqueta de texto sin más pasa fácilmente inadvertida en la barra.

Nunca la conviertas en un botón filled. Una acción lo bastante importante como para parecer que pide un botón filled no tiene sitio en un snackbar, que desaparece y es lo último a lo que se llega en el orden del foco. Ponla tras la acción principal de la pantalla, en una hoja inferior.

Un producto puede dar otro aspecto a la acción. Lo hace una sola vez, para todos los snackbars, en su capa de sistema de diseño, dando otros valores a los tokens de color de la acción y a la opacidad de su capa tonal; no hay una variante por snackbar. Los preajustes Material y Cupertino hacen exactamente eso, para conservar la acción de texto que tienen sus originales.

Formas de estado

status Glifo Se anuncia Úsala para
default Ninguno De forma cortés La mayoría de los mensajes: lo que la aplicación acaba de hacer.
info info De forma cortés Algo que vale la pena saber y que no es el resultado de una acción de la persona.
success check_circle De forma cortés Una tarea que terminó bien, cuando la persona la estaba esperando.
warning warning De forma asertiva Algo que puede ir mal si la persona no actúa.
error error De forma asertiva Un fallo al que la persona puede volver, con una acción que reintenta o explica.

Formas de estado: info, success, warning y error

Una forma de estado dibuja su barra como un tinte discreto del estado, rodeada por un borde de línea fina en el color del estado y con el glifo del estado, en ese color, antes del texto. El borde no ocupa espacio. La forma predeterminada no tiene un borde propio, solo el que dibuja su elevación. Una forma de estado nunca se comunica solo con el color: la forma del glifo distingue unas formas de otras, y statusLabel da el estado en palabras, en el idioma de tu producto («Error»). La etiqueta se lee antes del título y del mensaje. Las formas warning y error interrumpen lo que se está leyendo; las demás esperan a que termine.

Sobre una superficie o en inverso

De forma predeterminada, un snackbar se dibuja sobre una superficie elevada del esquema: la superficie clara, levantada por su elevación, sobre la que también se apoyan los diálogos, con el color de texto del esquema. Dibujado en inverso toma los colores del esquema opuesto, una barra oscura en un esquema claro, de modo que se distingue de aquello sobre lo que aparece.

Dibujado en inverso: la forma predeterminada y las cuatro formas de estado

inverse Se dibuja
Sin definir (null, el valor predeterminado) Como elija el sistema de diseño. El sistema predeterminado elige una superficie; el preajuste m3-like elige inverso.
true En inverso.
false Sobre una superficie, también en un sistema cuya elección es inverso.

En la web, el atributo indica cuál de los tres es: si se omite, está sin definir; inverse es true, e inverse="false" es false. show() admite inverse como opción.

Una forma de estado dibujada en inverso es la forma de ese estado en el otro tema, parte por parte. En un tema claro, la barra info en inverso es la barra info que dibuja un tema oscuro, con el texto, el glifo, el borde y la acción de ese tema; en un tema oscuro, es la del tema claro. Lo mismo vale en cada nivel de contraste. Así, una forma de estado en inverso no usa ningún color que el producto no dibuje ya en otro lugar, y su glifo y su borde son tan vivos como sobre una superficie.

Dibujarse en inverso cambia los colores y nada más: el tamaño, las esquinas, la elevación, la disposición, los glifos, el movimiento, los tiempos, el anuncio y las teclas siguen igual. Es un aspecto, no un significado. No lo uses para decir que un mensaje es importante; eso lo dicen las formas de estado y statusLabel. Es preferible decidirlo una sola vez para el producto, en su capa de sistema de diseño, para que todos los snackbars parezcan el mismo tipo de mensaje.

Texto largo

Mientras están contraídos, el título y el mensaje muestran como máximo tres líneas cada uno, y terminan con puntos suspensivos donde se cortan. Entonces aparece un botón de expandir entre la acción y el botón de cierre. Al activarlo se muestra todo el texto, se emite toggle con el nuevo valor de expanded (expandedchange en la web), el foco se queda en el botón y el snackbar no se cierra. La barra crece hacia arriba desde su borde inferior (o hacia abajo desde su borde superior cuando se coloca en el extremo superior final), de inmediato donde el movimiento está reducido. Su contenido se alinea arriba, de modo que el glifo, la primera línea y los controles que tiene al lado mantienen su distancia al borde superior mientras la barra crece o se encoge, y una acción en su propia fila mantiene su distancia al borde inferior. Tu código también puede definir expanded, lo que no emite nada.

Si el texto expandido sigue siendo más alto que el espacio que tiene el anfitrión, la barra toma esa altura y su texto se desplaza dentro de ella, mientras el glifo y los controles permanecen en su sitio. La tecnología de apoyo siempre recibe el texto entero, esté cortado o no.

Ubicación

placement Dónde está la barra Para qué usarlo
bottom (predeterminado) Abajo en la ventana, centrada, con un margen sobre el borde inferior. La mayoría de los productos, y cualquier producto en un teléfono.
top-end Arriba en la ventana, en el lado final: arriba a la derecha, o arriba a la izquierda en un diseño de derecha a izquierda. En una ventana compacta (de menos de 600 de ancho en el sistema predeterminado) ocupa en cambio todo el ancho de la parte superior. Las pantallas de escritorio de una aplicación de gestión, donde la parte inferior de la pantalla es donde está el trabajo.

Elige una sola ubicación para todo el producto y dásela al anfitrión, para que las personas aprendan dónde aparecen los mensajes: placement en <tanrei-snackbar-host> se aplica a cada snackbar que muestra, y un snackbar pedido con su propio placement lo conserva. En un teléfono, mantén la parte inferior, donde Material coloca el snackbar y donde está el pulgar. En las pantallas de escritorio de una aplicación de gestión, como un panel de control, una consola de administración o un editor cuya propia barra de herramientas, barra de estado o paginación de tabla está abajo, usa top-end, donde Carbon y Fluent colocan sus notificaciones.

En el extremo superior final, la barra queda a un margen del borde superior y del borde final, dentro del área segura y por debajo de una cabecera fija, de modo que nunca tapa la barra de aplicación superior. En la web lee la altura de la cabecera de --tanrei-app-shell-scroll-offset, que Estructura de la aplicación define en la raíz del documento; un producto con un marco propio define esa propiedad con la altura de su propia cabecera fija. Baja desde encima del borde superior en lugar de subir desde abajo, y una barra expandida crece hacia abajo. Nada más cambia: sigue habiendo un solo snackbar a la vez y nunca una pila, sus controles se siguen alcanzando en el lugar del anfitrión en el orden del foco y se anuncia de la misma manera.

<!-- Cada snackbar que muestra este anfitrión queda en el extremo superior final. -->
<tanrei-snackbar-host placement="top-end"></tanrei-snackbar-host>

<script type="module">
  const snackbars = document.querySelector('tanrei-snackbar-host');
  snackbars.show({ message: 'Report exported', action: 'Open' });
  // Un snackbar pedido abajo conserva su propia ubicación.
  snackbars.show({ message: 'Photo saved', placement: 'bottom' });
</script>
<SnackbarHost ref={snackbars} placement="top-end" />

SwiftUI, Compose, Flutter y React Native todavía no tienen la ubicación en el extremo superior final: sus snackbars quedan abajo.

Duración

duration Cuánto permanece por sí solo
auto (predeterminado) short sin acción. Con una acción nunca agota su tiempo, así que nadie se queda sin tiempo para usarla (WCAG 2.2.1).
short Se cierra tras el tiempo de espera corto (4 segundos en el sistema predeterminado).
long Se cierra tras el tiempo de espera largo (10 segundos en el sistema predeterminado).
indefinite Permanece hasta que la persona o tu código lo cierran.

Un snackbar temporizado se pausa mientras el puntero está sobre él, mientras el foco está dentro de él, mientras está expandido, mientras la aplicación está oculta o en segundo plano, y mientras lo cubre un diálogo modal de Tanrei. Después vuelve a empezar con su duración completa. El tiempo de espera de accesibilidad de Android lo alarga cuando es mayor, y un snackbar con una acción nunca agota su tiempo mientras hay un lector de pantalla en funcionamiento. Si pones un tiempo de espera a un snackbar que tiene una acción, ofrece también esa acción en otro lugar, como Deshacer en un menú. Las compilaciones de depuración te lo recuerdan.

Aparición, foco y cierre

Un snackbar es una superposición de lectura. Las personas asimilan su mensaje, así que mostrarlo nunca mueve el foco.

  • De uno en uno. El anfitrión muestra los snackbars en el orden en que se pidieron. El siguiente espera hasta que el anterior se ha desvanecido. Un snackbar pedido mientras hay un diálogo modal de Tanrei abierto espera hasta que el diálogo se cierra.
  • Ubicación. Abajo y centrado, con un margen sobre el borde inferior y desde los lados, dentro del área segura y por encima del teclado en pantalla; o, con placement="top-end", en el extremo superior final, por debajo de una cabecera fija (consulta Ubicación). En ambos casos se dibuja por encima del contenido de su área y por debajo de un diálogo modal y su velo.
  • Anuncio. Cuando aparece, la tecnología de apoyo lee una vez la etiqueta de estado, el título y el mensaje, seguidos de la etiqueta de la acción: de forma cortés, después de lo que se está leyendo, o de forma asertiva para warning y error. Nada toma el foco del teclado ni el del lector de pantalla.
  • Foco. A la acción, al botón de expandir y al botón de cierre se llega con Tab en el lugar del anfitrión en el orden del foco, y por eso el anfitrión va el último. La barra en sí no es una parada de tabulación, salvo su texto mientras una barra expandida lo desplaza.
  • Cierre. El snackbar se cierra cuando se activa su acción (action), o sin ella (dismiss), por uno de estos motivos:
Motivo Cuándo
close Se activó el botón de cierre.
escape Se pulsó Escape mientras el foco estaba dentro del snackbar.
timeout A un snackbar short o long se le acabó el tiempo.
host Tu código lo cerró o vació la cola.
  • Devolución del foco. Cuando un snackbar se cierra mientras el foco está dentro de él, el foco vuelve al elemento que lo tenía antes de que entrara en el snackbar.
  • Movimiento. Sube hasta su sitio desde debajo del borde inferior (o baja desde encima del borde superior en el extremo superior final) mientras aparece con un fundido, y se desvanece sin moverse de su sitio. Donde el movimiento está reducido, aparece y desaparece con un fundido, sin moverse; en Android, cuyo ajuste elimina todas las animaciones, aparece y desaparece de inmediato.

Recomendado

  • Di lo que ocurrió en pasado: «Mensaje enviado», «3 archivos movidos».
  • Da a la acción un verbo corto que las personas esperen después del mensaje: «Deshacer», «Ver», «Reintentar».
  • Elige el estado que corresponda a lo que ocurrió, y da un statusLabel a cada forma de estado.
  • Decide una sola vez, para todo el producto, si los snackbars se dibujan sobre una superficie o en inverso, y dónde se colocan.
  • Mantén el texto lo bastante corto como para que rara vez necesite el botón de expandir.
  • Conserva la duración predeterminada auto a menos que tengas un motivo. Nunca deja a nadie sin tiempo para usar una acción.
  • Pon el anfitrión el último en la página o en el diseño, para que sus controles sean los últimos en el orden del foco.

Evita

  • No uses un snackbar para errores que bloquean la tarea ni para preguntas. Usa un diálogo.
  • No pongas dos acciones en un snackbar. Tiene sitio para una.
  • No conviertas la acción en un botón filled, ni pongas en un snackbar una acción que parezca necesitarlo. Usa una hoja inferior desde la acción principal.
  • No uses la forma warning o error para confirmaciones rutinarias. Interrumpen al lector de pantalla.
  • No dibujes un snackbar en inverso para marcarlo como importante. El inverso solo cambia los colores; un estado dice qué tipo de mensaje es.
  • No muestres un snackbar para algo que la pantalla ya muestra con claridad.
  • No muevas el foco a un snackbar ni a su acción. No debe apartar a las personas de su trabajo.

Accesibilidad

Rol
status
Etiquetado
The snackbar is a live region: polite in the default, info and success forms (the status role on the web) and assertive in the warning and error forms (the alert role on the web). When it appears it announces, once, statusLabel, the title, the whole message and the action's label. The status glyph is hidden from assistive technology; statusLabel gives the status in words. The action's name is its label; the close button's name is closeLabel; the expand button's name is expandLabel, and it exposes whether the text is expanded. The bar itself is not a tab stop; its text is one only while it scrolls.
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 Reaches, at the host's place in the focus order, the text while it scrolls, then the action, the expand button and the close button. Showing a snackbar never moves focus.
Enter / Space Activates the focused action, expand button or close button.
Arrow keys, Page Up, Page Down While the expanded text scrolls and has focus, scroll it.
Escape While focus is inside the snackbar, closes it (dismiss, reason escape).

Notas

  • WCAG 2.2.1 (timing adjustable): by default (auto) a snackbar with an action never times out. A product may time one out (short or long), but then the action must also be available elsewhere (Undo in a menu or a history), because a person who is slow, zoomed-in or using a screen reader may not reach it in time. The timeout pauses while the snackbar is hovered, focused or expanded, and Android's accessibility timeout lengthens it.
  • A snackbar reports; it does not ask. A choice between two actions, an error that blocks the person's work, or anything they must acknowledge belongs in a dialog or next to what it is about. The error form is for a failure the person can come back to (a message not sent, with Retry).
  • The action is a tonal button so that an undo is seen at once: its label is the strongest thing in it (at least 9.1:1 on the action at rest and 6.9:1 in its weakest state, in every form and scheme of the default system), and the action is one quiet step off its bar, the same step in every form (1.25–1.45:1 against the bar in all ten forms and six schemes), so it never outweighs the message and never weighs more on one status than on another. A button with a visible label needs no boundary contrast (WCAG 1.4.11). An action important enough to seem to want a filled button does not belong in a snackbar: put a Main Action Button in a bottom sheet instead.
  • WCAG 2.4.13 and 1.4.11 (focus appearance, non-text contrast): the focus indicator is drawn on the bar, so its color is the form's (SNK-3). On the default form's surface it is the system's focus color, which the build holds against every surface role; on a status bar and on an inverse bar it is that bar's content color, which the build holds against the bar at 4.5:1 or more. The system's focus color alone is held against no status bar and falls under 3:1 on the inverse surface in five of the six schemes.
  • Drawn inverse or not, a snackbar is the same message: the role, the announcement, the focus order and the timing do not change with its colors (SNK-30). A product should not use inverse to mean something (an inverse bar for important messages): that is what the status forms and statusLabel are for.
  • WCAG 1.4.1 (use of color): a status form is never told by color alone. It draws the status's glyph, a shape of the icon set, and gives statusLabel, the status in words, to assistive technology (SNK-21).
  • WCAG 1.4.3 and 1.4.11 (contrast): three parts are drawn at an opacity of their own color, so their contrast is that of the color as drawn, not of the role. In the default system the message under a title keeps at least 7.1:1 on its bar (7.6:1 in the high-contrast schemes) and the status glyph at least 3.6:1, in every form and scheme (SNK-32, SNK-21); a status form's edge is decoration beside the glyph and statusLabel and is held to nothing (SNK-31). A system that changes one of these opacities, or the colors under them, must keep 4.5:1 for the message and 3:1 for the glyph.
  • WCAG 1.4.11 (non-text contrast): the expand and close buttons are Buttons in the form's tone (SNK-34): the glyph is the bar's message color, and the circle under it is that color at comp.button.tone.container.opacity over the bar. In the default system the glyph keeps at least 8.0:1 against its circle at rest and 6.2:1 in its weakest states (focused and pressed), in all ten forms and six schemes — well above the 3:1 a glyph without a label needs. A system that changes the tone's opacity, the state-layer opacities or a form's colors must keep 3:1 for the glyph against the circle in every state.
  • Text size never hides text for good: a collapsed title or message ends with an ellipsis at its line limit and the expand button shows the rest (SNK-23); the action moves to its own row (SNK-16); an expanded bar taller than the window scrolls inside it (SNK-25).
  • Web: `<tanrei-snackbar-host>` is placed by the product, normally as the last element of the page (its place in the focus order). It shows `<tanrei-snackbar>` elements as `popover="manual"`, so they are in the top layer, and exposes `show(options): Promise<{ result: 'action' | 'dismiss', reason? }>` (whose options include `inverse`), `dismissCurrent()` and `clear()`. The live regions are the host's two, which are always in the document, so screen readers register them before the first message is inserted: one with the status role (polite) for the default, info and success forms, one with the alert role (assertive) for warning and error. The expand button carries `aria-expanded` and `aria-controls` naming the text.
  • SwiftUI, Compose, Flutter and React Native announce with the platform's own call, at default priority for the polite forms and at high priority for warning and error: AccessibilityNotification.Announcement with the speech announcement priority, a polite or assertive liveRegion, SemanticsService.announce with its assertiveness, and AccessibilityInfo.announceForAccessibility (announceForAccessibilityWithOptions with queue off for assertive on iOS). None of them takes focus. The expand button's state is the platform's expanded/collapsed semantics (Compose's expand and collapse actions, Flutter's expanded flag, React Native's accessibilityState.expanded, and on Apple platforms the expanded and collapsed value VoiceOver reads for a disclosure).
  • How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.

Generado a partir de specs/snackbar.spec.json, tokens/sys/measure.tokens.json

De qué se encarga el componente

  • El snackbar se anuncia mediante una región activa (live region): una cortés (el rol status en la web) para las formas default, info y success, y una asertiva (el rol alert) para warning y error. Su etiqueta de estado, su título y su mensaje, y después la etiqueta de su acción, se anuncian una vez cuando aparece, y siempre enteros, incluso cuando el texto está cortado. En SwiftUI, Compose, Flutter y React Native se usa el anuncio propio de la plataforma, con prioridad alta para warning y error, y ninguno de ellos toma el foco.
  • Una forma de estado nunca se comunica solo con el color: dibuja el glifo del estado y expone statusLabel como texto antes del título. El glifo en sí queda oculto para la tecnología de apoyo, igual que los glifos de expandir y de cierre.
  • La acción recibe su nombre de su etiqueta, el botón de expandir de expandLabel y el botón de cierre de closeLabel. A todos se llega con Tab en el lugar del anfitrión en el orden del foco, y se activan con Enter o Espacio.
  • El botón de expandir expone si el texto está expandido y conserva el mismo nombre en los dos estados. Una barra expandida cuyo texto se desplaza convierte el texto en una parada del foco, que recibe su nombre del título y se desplaza con las teclas de flecha y con Re Pág y Av Pág.
  • Escape cierra el snackbar mientras el foco está dentro de él. Cuando se cierra con el foco dentro, el foco vuelve adonde estaba antes.
  • El lugar donde está la barra no cambia nada más. Un snackbar en el extremo superior final se alcanza con Tab en el lugar del anfitrión en el orden del foco, se anuncia exactamente igual que uno abajo y nunca tapa una cabecera fija.
  • Un snackbar con una acción no agota su tiempo de forma predeterminada. Los snackbars temporizados se pausan mientras tienen el cursor encima, el foco o están expandidos, se alargan hasta el tiempo de espera de accesibilidad de Android y, con una acción, nunca agotan su tiempo mientras hay un lector de pantalla en funcionamiento.
  • La acción cumple el objetivo mínimo en los dos ejes sin cambiar su tamaño dibujado, y los botones de expandir y de cierre, que son Button, conservan el suyo. Todo anillo de foco se muestra solo para el foco del teclado, en un color de la forma del snackbar, de modo que se ve en cualquier barra: una superficie, el tinte de un estado y una barra en inverso.
  • Los glifos de expandir y de cierre mantienen al menos 3:1 frente a su círculo en todos los estados y formas. En el sistema predeterminado mantienen al menos 8.0:1 en reposo, y 6.2:1 con el foco o al pulsarlos.
  • Las partes que se dibujan más suaves mantienen su contraste frente a la barra en todos los esquemas del sistema predeterminado: el glifo de estado, al menos 3:1, y un mensaje bajo un título, al menos 4.5:1, o 7:1 en los esquemas de contraste alto. La suavización es solo cuestión de color; lo que lee la tecnología de apoyo no cambia, y tampoco cuando el snackbar se dibuja en inverso.
  • Un texto más grande nunca oculta texto de forma definitiva: un título o un mensaje contraídos terminan con puntos suspensivos a las tres líneas y el botón de expandir muestra el resto, la acción pasa a su propia fila, y una barra expandida más alta que la ventana se desplaza.
  • Antes de que se haya cargado la fuente de iconos, el nombre de un glifo nunca se dibuja como texto: el lugar del glifo queda vacío hasta que la fuente puede dibujarlo.
  • Las compilaciones de depuración notifican un mensaje vacío, un botón de cierre sin closeLabel, una forma de estado sin statusLabel, un botón de expandir sin expandLabel y un snackbar temporizado que tiene una acción.

Carencias conocidas por plataforma:

  • Web: el navegador no dice si hay un lector de pantalla en funcionamiento y no tiene tiempo de espera de accesibilidad, así que ninguno de los dos alarga un snackbar temporizado. La duración predeterminada auto es lo que mantiene una acción al alcance.
  • Web: que se mantenga apartado del teclado en pantalla todavía no se ha comprobado en un dispositivo que lo tenga.
  • SwiftUI no puede devolver el foco al elemento que lo tenía: cuando un snackbar se cierra con el foco dentro, el foco va adonde SwiftUI lo mueve cuando se elimina una vista. Un anfitrión dentro de una vista que alojas fuera de una escena, como tu propio NSHostingView, nunca ejecuta sus tiempos de espera.
  • Compose no puede nombrar el elemento que tenía el foco antes de que entrara en el snackbar. Cuando el snackbar se cierra con el foco dentro, el foco sale por donde entró: después de entrar con Tab, va al elemento anterior al anfitrión. Cuando tu código lo cierra mientras el foco está dentro, el foco no se mueve.
  • Compose: el alargamiento hasta el tiempo de espera de accesibilidad de Android y la pausa mientras la ventana está oculta todavía no están cubiertos por ninguna prueba.
  • Compose: el anuncio cortés, la pausa mientras la ventana no tiene el foco y el tiempo de espera de accesibilidad se han probado solo con Robolectric, todavía no en un dispositivo.
  • Flutter todavía no alarga un snackbar temporizado hasta el tiempo de espera de accesibilidad de Android, que Flutter no expone.
  • React Native no puede saber qué elemento tenía antes el foco. Cuando un snackbar se cierra mientras el foco está dentro de él, el foco va adonde lo pone la plataforma.
  • React Native no tiene una API propia de área segura. El snackbar se mantiene dentro del área segura solo cuando pasas los márgenes interiores de la ventana a TanreiProvider; sin ellos, en un teléfono con indicador de inicio puede quedar en parte encima de él.
  • React Native decide que la acción pasa a su propia fila a partir de las líneas ya dispuestas, así que el cambio ocurre después de la primera pasada de diseño.
  • React Native: el anuncio cortés, que se mantenga por encima del teclado y las pausas por el segundo plano y por el puntero todavía no se han comprobado en un dispositivo.

Qué debes hacer tú

  • Escribe el mensaje como texto sin formato que tenga sentido por sí solo al leerse en voz alta.
  • Da un closeLabel al botón de cierre, un statusLabel a una forma de estado y un expandLabel a un snackbar cuyo texto pueda alargarse, todos en el idioma de tu producto.
  • Coloca el anfitrión el último en la página, o el último en el diseño en Compose.
  • En React Native, pasa los insets de la ventana a TanreiProvider, para que el snackbar se mantenga apartado de las barras del sistema.
  • Si eliges short o long para un snackbar con una acción, ofrece la misma acción en algún lugar que no agote su tiempo.
  • Pon en un diálogo, no en un snackbar, todo aquello sobre lo que las personas deban actuar.