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
InicioComponentesInsignia

Insignia

Marca un icono, un elemento de navegación o un avatar con un punto o un número pequeño para indicar que hay algo pendiente.

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

Descripción general

Web
tanrei-badge
schedule
SwiftUI
TanreiBadge
schedule
Jetpack Compose
TanreiBadge
schedule
Flutter
TanreiBadge
schedule
React Native
Badge
schedule

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

Un punto y un número

chatinboxnotifications

Uso

<!-- Sin count: el punto. Un punto necesita una etiqueta. -->
<tanrei-badge label="Mensajes nuevos">
  <tanrei-button variant="text" label="Chat"><span slot="icon">chat</span></tanrei-button>
</tanrei-badge>

<!-- 0 no dibuja nada; un número por encima de max (999) se muestra como 999+. -->
<tanrei-badge count="3" label="3 sin leer">
  <tanrei-button variant="text" label="Bandeja de entrada"><span slot="icon">inbox</span></tanrei-button>
</tanrei-badge>

<script type="module">
  import '@tanrei/web/components/badge';
  import '@tanrei/web/components/button';
  const badge = document.querySelector('tanrei-badge[count]');
  badge.count = unread;
  badge.label = `${unread} sin leer`;
</script>
import { Badge, Button } from '@tanrei/react';

<Badge label="Mensajes nuevos">
  <Button variant="text" label="Chat" onClick={openChat}><span slot="icon">chat</span></Button>
</Badge>
<Badge count={unread} label={`${unread} sin leer`}>
  <Button variant="text" label="Bandeja de entrada" onClick={openInbox}><span slot="icon">inbox</span></Button>
</Badge>
import Tanrei

// nil es el punto.
TanreiBadge(count: nil, label: "Mensajes nuevos") {
  TanreiIconButton("Chat", action: openChat) { Image(systemName: "bubble.left") }
}
TanreiBadge(count: unread, label: "\(unread) sin leer") {
  TanreiIconButton("Bandeja de entrada", action: openInbox) { Image(systemName: "tray") }
}

// Lo mismo como modificador de cualquier vista.
Image(systemName: "bell").accessibilityLabel("Notificaciones").tanreiBadge(1200, label: "Más de 999 sin leer")
import io.github.chnotchy.tanrei.components.TanreiBadge
import io.github.chnotchy.tanrei.components.TanreiIconButton
import io.github.chnotchy.tanrei.primitives.TanreiText

// null es el punto.
TanreiBadge(count = null, contentDescription = "Mensajes nuevos") {
    TanreiIconButton(onClick = ::openChat, contentDescription = "Chat") { TanreiText("chat") }
}
TanreiBadge(count = unread, contentDescription = "$unread sin leer") {
    TanreiIconButton(onClick = ::openInbox, contentDescription = "Bandeja de entrada") { TanreiText("inbox") }
}
import 'package:tanrei/tanrei.dart';

// Sin count: el punto.
TanreiBadge(
  semanticLabel: 'Mensajes nuevos',
  child: TanreiIconButton(onPressed: openChat, semanticLabel: 'Chat', icon: const Icon(AppSymbols.chat)),
);
TanreiBadge(
  count: unread,
  semanticLabel: '$unread sin leer',
  child: TanreiIconButton(onPressed: openInbox, semanticLabel: 'Bandeja de entrada', icon: const Icon(AppSymbols.inbox)),
);
import { Badge, IconButton } from '@tanrei/react-native';

<Badge label="Mensajes nuevos">
  <IconButton accessibilityLabel="Chat" onPress={openChat}>chat</IconButton>
</Badge>
<Badge count={unread} label={`${unread} sin leer`}>
  <IconButton accessibilityLabel="Bandeja de entrada" onPress={openInbox}>inbox</IconButton>
</Badge>

Especificaciones

Números y el tope

notificationsnotificationsnotificationsnotificationsnotificationsnotifications

Anatomía

Anatomía

Dibujado sobre el fixture count-single, tal como lo dibuja el paquete web.
Parte Descripción
1 container The pill that holds the count: at least as wide as it is high, so a single digit sits in a circle.
2 dot · opcional The container's form when there is no count: a small circle with no label.
3 label · opcional The count, or the capped count followed by a plus sign.
4 outline A ring outside the dot or the pill that separates the badge from what it overlaps.

Medidas

Medidas

Longitud Token Valor (px)
container padding-inline tanrei.comp.badge.container.padding-inline 4
container height tanrei.comp.badge.container.height 16
Dibujado sobre el fixture count-single, tal como lo dibuja el paquete web.

Propiedades

Propiedad Tipo Valor predeterminado Descripción
count number null How many things are waiting. Null draws the dot (something is new, the number is unknown or unimportant); 0 draws nothing; above 0 draws the number.
max number 999 The largest count shown as it is; a larger one shows as max followed by a plus sign (999+).
label string "" What assistive technology reads after the anchor's own name ("3 unread"). With no label, the displayed count is read; a dot needs one.

Slots

Slot Descripción
default The anchor the badge sits on, which it needs: an icon, an icon-only Button, a navigation item or an avatar. Its first element is the anchor; a badge with no element to sit on draws nothing (BDG-16). In fixtures the anchor is the glyph of the system's icon set that the fixture's content names, drawn at the icon size sys.icon.medium in the color on-surface-variant; its accessible name is that glyph name ("mail"), and the badge adds the fixture's label to it as its value ("mail, 3 unread").

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
BDG-1 WHILE count is null THE badge SHALL draw a circle of diameter comp.badge.dot.size in comp.badge.container.color with no label, its center comp.badge.dot.offset inside the anchor's top-end corner on both axes; the dot is a circle whatever corners the container has.
BDG-2 WHILE count is above 0 THE badge SHALL draw a container at least comp.badge.container.height high and at least as wide as it is high, with comp.badge.container.padding-inline on each side of its label and corners of comp.badge.container.shape, filled with comp.badge.container.color, and the label centered in comp.badge.label.typescale and comp.badge.label.color.
BDG-3 WHILE count is above 0 THE badge SHALL place the center of the container's leading circle (a square of the container's drawn height at its start) comp.badge.container.offset inside the anchor's top-end corner on both axes, so that a longer count grows toward the end, away from the anchor.
BDG-4 WHEN count is greater than max THE badge SHALL show max followed by a plus sign (999+ with the default max) instead of count, and SHALL otherwise show count in full.
BDG-5 WHILE count is 0 THE badge SHALL draw nothing and expose nothing to assistive technology, and its anchor SHALL render and be announced as it would without a badge.
BDG-6 THE badge SHALL draw comp.badge.outline.width of comp.badge.outline.color around the dot or the container, outside its edge, without changing the badge's size or position.
BDG-7 THE badge SHALL NOT change its anchor's size or position, SHALL NOT take space in the layout (it may extend past the anchor's bounds), and SHALL NOT take pointer, touch or keyboard input: input over the badge reaches the anchor.
BDG-8 THE badge SHALL hide its drawn dot and number from assistive technology and SHALL add label to its anchor's accessible description, so that the anchor is announced with its own name followed by label; WHILE label is empty and count is above 0 THE badge SHALL add the displayed text instead (for example 999+).
BDG-9 WHILE count is null and label is empty THE badge SHALL still render, and in debug builds report that the dot tells assistive technology nothing.
BDG-10 WHEN count or label changes THE badge SHALL update its anchor's accessible description and SHALL NOT announce the change by itself.
BDG-11 WHERE the layout direction is right-to-left THE badge SHALL take the anchor's top-left corner as its top-end corner and grow toward the left, and SHALL isolate its label from the surrounding direction so that a capped count keeps its plus sign after the digits.
BDG-12 THE badge SHALL format count and max with the current locale's digits and no grouping separator, and SHALL draw digits with tabular figures where the font has them, so that a changing count does not shift its neighbours.
BDG-13 WHILE the text size is enlarged THE badge SHALL grow its container with its label, keep the center of the leading circle — a square of the grown container's height — at its placement, and keep the dot at comp.badge.dot.size.
BDG-14 IF count is negative or not a number THE badge SHALL render as for 0; IF count is not a whole number THE badge SHALL use it rounded down; IF max is below 1 THE badge SHALL use its default of 999; in each case debug builds SHALL report the value.
BDG-15 THE badge 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 badge is shown THE badge SHALL draw itself for the new direction at once, without a motion of its own, keeping what it shows and its state.
BDG-16 IF the badge has no anchor THE badge SHALL draw nothing, take no space and expose nothing to assistive technology, whatever its count and label, and in debug builds report that a badge needs an anchor; WHEN an anchor is given to it THE badge SHALL draw itself on that anchor (BDG-1, BDG-3) and describe it (BDG-8) at once, and WHEN its anchor is taken away it SHALL give the anchor back its own description and draw nothing again.

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-badge TanreiBadge TanreiBadge TanreiBadge Badge
count · Propiedad count count count count count
max · Propiedad max max max max max
label · Propiedad label label contentDescription semanticLabel label
Notas Wraps its anchor in the default slot. No count attribute is the dot. The badge sets aria-description on the slotted anchor and keeps its own shadow content aria-hidden. TanreiBadge(count: Int?, max:, label:) { anchor }, with a .tanreiBadge(_:max:label:) modifier for the same view (SwiftUI's own .badge works only in lists and tab bars). count: nil is the dot. One composable plays Material's BadgedBox and Badge together: TanreiBadge(count: Int?, max, contentDescription) { anchor }. count = null is the dot. As Flutter's Badge.count, with the anchor as child; count: null is the dot (Flutter's plain Badge). The anchor is children. label is appended to the anchor's accessibilityValue.text, not set as the badge's own accessibilityLabel: the badge itself is not an accessibility element.

Tokens

Token Alias de Valor resuelto (claro)
--tanrei-comp-badge-container-color sys.color.primary #1b1b1b
--tanrei-comp-badge-container-height — 16px
--tanrei-comp-badge-container-offset sys.space.space0 0px
--tanrei-comp-badge-container-padding-inline sys.space.space50 4px
--tanrei-comp-badge-container-shape sys.shape.corner.full 9999px
--tanrei-comp-badge-dot-offset sys.space.space25 2px
--tanrei-comp-badge-dot-size — 6px
--tanrei-comp-badge-label-color sys.color.on-primary #ffffff
--tanrei-comp-badge-outline-color sys.color.surface #ffffff
--tanrei-comp-badge-outline-width sys.border.thick 2px
--tanrei-comp-badge-label-typescale sys.typescale.label-small 500 12px/1.3333

Fixtures

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

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

Pautas

Cuándo usarlo

Usa una insignia para indicar que hay algo pendiente detrás de un icono, un elemento de navegación o un avatar: mensajes sin leer, actividad nueva, actualizaciones por instalar. Dirige la mirada hacia el lugar donde la persona puede actuar. Una insignia no tiene texto ni un lugar propio en el diseño de página, así que no es una etiqueta de estado. Para una palabra que nombra un estado o una categoría, como «Nuevo», «Beta» o «Pro», usa un tag.

Insignia, chip o tag

Los tres se distinguen por lo que hacen:

Tipo Qué es Dónde está Recibe entrada
Insignia Un punto o un número unido a otro elemento. En la esquina de su ancla, fuera del diseño de página. No. La entrada llega al ancla.
Chip Un control. En el diseño de página. Sí: se pulsa, se conmuta o se quita, y tiene foco y estados.
Tag Un rótulo estático. En el diseño de página, en línea. Nunca.
  1. Si es un número o un punto encima de otra cosa, es una insignia.
  2. Si se pulsa, se selecciona o se quita, es un chip. Si lleva a algún sitio, es un enlace.
  3. Si es una palabra que solo dice qué es una cosa o en qué estado está, es un tag.

Un número que aparece por sí solo en una fila, como la cantidad de resultados junto a un encabezado, tampoco es una insignia: una insignia siempre tiene un ancla, y una que no tiene dónde situarse no dibuja nada. Escribe ese número como texto, leído en su lugar junto con las demás palabras de la fila: al final de un elemento de un panel de navegación es el trailingText del elemento. Cuando nombre un estado, usa un tag.

Cómo elegir una forma

La forma depende de count, así que no hay ninguna variante que elegir.

Forma count Úsala para
Punto ninguno (null) Hay algo nuevo, y la cantidad se desconoce o no importa.
Número mayor que 0 La cantidad ayuda a la persona a decidir si mirar ahora: mensajes sin leer, solicitudes pendientes.
Nada 0 No hay nada pendiente. Vincula la insignia directamente al número; no necesitas rodearla de una condición.

Un número por encima de max se muestra como max+ (999+ de forma predeterminada), de modo que la insignia nunca pasa de cuatro caracteres. Reduce max (a 99, por ejemplo) cuando el ancla sea pequeña o la cantidad exacta deje de importar antes.

Recomendado

  • Dale a cada insignia una etiqueta que se lea bien después del nombre del ancla: «3 sin leer» después de «Bandeja de entrada». Un punto la necesita más que ninguna otra forma, porque sin ella el punto no le dice nada a un lector de pantalla.
  • Deja espacio alrededor del ancla. La insignia se sitúa en su esquina superior del lado de fin y puede sobresalir de sus límites; nunca mueve el ancla ni le cambia el tamaño.
  • Quita la insignia cuando la persona haya visto aquello a lo que apunta, para que siga significando algo.

Evita

  • No pongas una insignia en cada elemento. Cuando todo está marcado, nada destaca.
  • No pongas una insignia sobre la etiqueta de un botón ni dentro de un texto corrido. Su lugar es un icono, un elemento de navegación o un avatar. Una palabra junto a una etiqueta o en una línea de texto es un tag.
  • No uses el color de la insignia para decir qué tipo de cosa está pendiente ni lo urgente que es. Dilo en la etiqueta, o en el contenido al que apunta.
  • No hagas interactiva la insignia. Los toques y los clics sobre ella llegan al ancla, que es donde está la acción.

Accesibilidad

Rol
none
Etiquetado
The badge has no role or name of its own. label (or, without one, the displayed count) becomes part of the anchor's accessible description, so the anchor is announced as, for example, "Inbox, button, 3 unread". The drawn number is hidden, so it is never read twice.
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

Notas

  • Not interactive: the badge takes no input (BDG-7), so the minimum target is the anchor's and the badge never shrinks or covers it for input.
  • A dot conveys its meaning by color and position only, so a dot without a label fails for screen reader users (BDG-9); give it one ("new messages").
  • Where the count must be announced when it changes (a live chat), the product uses a live region; the badge does not announce by itself (BDG-10).
  • A badge marks an anchor and never stands alone in a line or a row (BDG-16). A count that stands by itself, such as the count at the end of a navigation drawer's row, a tree view's row or a menu item, is text, read in its place as the row's own words: that component's trailing text. A word that names a state is a tag.
  • How the description reaches the anchor is each platform's idiom: the web sets it on the slotted anchor (an ID reference cannot cross the shadow root), Apple platforms append it to the anchor's accessibility value, Compose merges it into the anchor's semantics as a state description, Flutter adds it to the anchor's semantics value, React Native to its accessibility value.

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

De qué se encarga el componente

  • El punto y el número dibujados quedan ocultos para la tecnología de apoyo, de modo que el número nunca se lee dos veces.
  • La etiqueta (o, si no la hay, el número mostrado, como «999+») pasa a formar parte del ancla, de modo que el ancla se anuncia una sola vez con ambos: «Bandeja de entrada, botón, 3 sin leer». Cada plataforma usa su estilo propio: un aria-description en el ancla en la web, el valor de accesibilidad en las plataformas de Apple, Flutter y React Native, y una descripción de estado en Compose.
  • Un número igual a 0 no añade nada: el ancla se anuncia como se anunciaría sin insignia.
  • Una insignia sin ancla no dibuja nada, no ocupa espacio y no dice nada, y las compilaciones de depuración lo notifican. Si más tarde recibe un ancla, se dibuja sobre ella en ese mismo momento.
  • Un cambio de número o de etiqueta actualiza lo que dice el ancla, sin un anuncio que interrumpa a la persona.
  • No recibe entrada ni ocupa espacio, así que el área de pulsación del ancla queda intacta.
  • Un punto sin etiqueta, un número negativo y un max inferior a 1 se notifican en las compilaciones de depuración.

Qué debes hacer tú

  • Escribe una etiqueta que complete el nombre del ancla en lugar de repetirlo: «3 sin leer», no «La bandeja de entrada tiene 3 mensajes sin leer».
  • Haz que el ancla sea un solo elemento con nombre propio, como un botón de icono con etiqueta. En Compose, un icono simple que no está dentro de un elemento que fusiona a sus descendientes necesita uno a su alrededor para que el nombre y la etiqueta se lean juntos.
  • Si un cambio debe anunciarse en el momento en que ocurre, como en un chat en vivo, anúncialo desde tu producto con una región activa (live region). La insignia no anuncia.