Componentes · Ola 4 · Editorial
Chip
Una etiqueta corta con borde y un conteo opcional: un tema, un filtro. Estático, link o activable, y en grupo de selección única. Tiene 32 px de alto, un borde de 1 px y radio de 2 px; activo o actual, toma el fondo de la selección: blanco en Arche y el acento en cada producto.
import { Chip, ChipGroup } from '@archeblack/ui';
Ejemplos
Estáticos
Los temas del colofón de un post: texto, sin foco ni hover. Con items, ChipGroup es una lista.
- Filosofía
- Cultura
<script lang="ts">
import { ChipGroup } from '@archeblack/ui';
</script>
<!-- Los temas del colofón de un post: chips estáticos, en una lista. -->
<ChipGroup aria-label="Temas" items={[{ label: 'Filosofía' }, { label: 'Cultura' }]} /> Links a los temas
Cada tema lleva a su archivo, con su conteo. El actual (current) lleva aria-current="page" y la selección: en Arche y en Hermes.
<script lang="ts">
import '@archeblack/ui/products/hermes.css';
import { ChipGroup } from '@archeblack/ui';
// Los temas de Hermes con sus artículos. En la página de un tema, ese chip es el actual.
const topics = [
{ label: 'Filosofía', slug: 'filosofia', count: 4 },
{ label: 'Cultura', slug: 'cultura', count: 3 },
{ label: 'Videojuegos', slug: 'videojuegos', count: 2 },
{ label: 'Tecnología', slug: 'tecnologia', count: 1 }
];
</script>
<!-- Links a cada tema, con su conteo. El actual lleva aria-current="page" y la selección:
blanca en Arche y el acento en Hermes. -->
<div style="display: grid; gap: var(--arche-spacing-5); width: 100%">
{#each [undefined, 'hermes'] as product (product ?? 'arche')}
<ChipGroup
data-product={product}
aria-label="Temas"
items={topics.map((topic) => ({
label: topic.label,
href: `#${topic.slug}`,
current: topic.slug === 'cultura',
count: topic.count,
countLabel: topic.count === 1 ? '1 artículo' : `${topic.count} artículos`
}))}
/>
{/each}
</div> Selección única
El filtro de las publicaciones: ChipGroup con options y bind:value. Es un radiogroup: prueba con Tab y las flechas.
Tema elegido: Todas
<script lang="ts">
import '@archeblack/ui/products/hermes.css';
import { ChipGroup } from '@archeblack/ui';
let topic = $state('all');
const options = [
{ value: 'all', label: 'Todas', count: 5 },
{ value: 'filosofia', label: 'Filosofía', count: 4 },
{ value: 'cultura', label: 'Cultura', count: 3 },
{ value: 'videojuegos', label: 'Videojuegos', count: 2 },
{ value: 'tecnologia', label: 'Tecnología', count: 1 }
].map((option) => ({
...option,
countLabel: option.count === 1 ? '1 artículo' : `${option.count} artículos`
}));
const chosen = $derived(options.find((option) => option.value === topic)?.label);
</script>
<!-- El filtro de las publicaciones: una sola opción a la vez. Es un radiogroup: Tab entra en la
elegida y las flechas cambian la selección. -->
<div data-product="hermes" style="display: grid; gap: var(--arche-spacing-3); width: 100%">
<ChipGroup aria-label="Filtrar publicaciones por tema" {options} bind:value={topic} />
<p style="margin: 0; color: var(--arche-color-text-muted)">
Tema elegido: {chosen}
</p>
</div> Activables
Varios a la vez: cada chip es un botón con aria-pressed y bind:pressed. Deshabilitado, el texto y el borde se apagan.
<script lang="ts">
import { Chip } from '@archeblack/ui';
let filosofia = $state(true);
let cultura = $state(false);
let videojuegos = $state(false);
</script>
<!-- Chips activables, para elegir varios temas a la vez. Cada uno es un botón con aria-pressed;
el grupo lleva su nombre con role="group". -->
<div
role="group"
aria-label="Temas de la búsqueda"
style="display: flex; flex-wrap: wrap; gap: var(--arche-spacing-2)"
>
<Chip label="Filosofía" bind:pressed={filosofia} />
<Chip label="Cultura" bind:pressed={cultura} />
<Chip label="Videojuegos" bind:pressed={videojuegos} />
<Chip label="Tecnología" pressed={false} disabled />
</div> Conteo
La cifra en mono, con countLabel para leerla con su unidad.
<script lang="ts">
import { Chip } from '@archeblack/ui';
</script>
<!-- El conteo va en mono con cifras tabulares. countLabel dice cómo se lee: el lector de pantalla
oye «Publicaciones 5 resultados» y no solo la cifra. -->
<div style="display: flex; flex-wrap: wrap; gap: var(--arche-spacing-2)">
<Chip label="Todo" count={7} countLabel="7 resultados" />
<Chip label="Publicaciones" count={5} countLabel="5 resultados" />
<Chip label="Temas" count={2} countLabel="2 resultados" />
</div> Props
Chip
| Prop | Descripción |
|---|---|
label? string | El texto del chip. |
children? Snippet | Contenido propio en lugar de label. |
count? number | string | Un conteo al final, en IBM Plex Mono de 12 px con cifras tabulares, en text-subtle. |
countLabel? string | Cómo se lee el conteo («3 artículos»). El lector de pantalla oye este texto; en la pantalla se ve la cifra. |
href? string | Con href, el chip es un <a>. |
current? boolean | Solo con href: la página actual. Pone aria-current="page" y el aspecto de la selección. |
bind:pressed? boolean | Con pressed (aunque sea false), el chip es un <button aria-pressed> que se prende y se apaga. |
onPressedChange? (pressed: boolean) => void | Se llama al prender o apagar, con el valor nuevo, después de actualizar pressed y solo si el cambio se aceptó. |
disabled? boolean Por defecto false | Solo en un chip activable. |
class? ClassValue | Se suma a arche-chip. |
...rest HTMLAttributes | Van al elemento: <span>, <a> o <button>. |
ChipGroup
| Prop | Descripción |
|---|---|
options? ChipGroupOption[] | Selección única: { value, label, count?, countLabel?, disabled? }. El grupo es un radiogroup de Bits UI y cada opción, un chip con role="radio". |
bind:value? string | Con options: el valor elegido. |
onValueChange? (value: string) => void | Con options: se llama al elegir otra opción, después de actualizar value y solo si el cambio se aceptó. |
name? string | Con options: el nombre del campo para enviar el formulario. |
required? boolean Por defecto false | Con options y name: exige elegir una opción. |
disabled? boolean Por defecto false | Con options: deshabilita todo el grupo. |
items? ChipGroupItem[] | Lista: las props de un Chip por ítem (y una key opcional). El grupo es un <ul> con un <li> por chip. |
aria-label | aria-labelledby? string | El nombre del grupo. Obligatorio con options (TypeScript lo exige); opcional en una lista. |
class? ClassValue | Se suma a arche-chip-group. |
...rest HTMLAttributes | Van al radiogroup o al <ul>. |
Accesibilidad
- El elemento sale de las props: sin
hrefnipressedes texto (<span>), conhrefun link y conpressedun botón conaria-pressed. Un chip estático no recibe el foco ni cambia con el puntero. - El chip actual de una lista de links lleva
aria-current="page": el lector anuncia «página actual», además del fondo de la selección. - Un grupo de selección única es un
radiogroupcon nombre: una sola parada del tabulador, las flechas mueven la selección y el lector anuncia «1 de 5». No es una fila de botones conaria-pressed, que se leerían como interruptores sueltos. - Con
countLabel, el conteo se lee como texto («Filosofía 4 artículos»); sin él, la cifra sola es parte del nombre. - Mide al menos 32 px de alto (WCAG 2.5.8). El foco es el anillo de Arche; activo y con foco, el halo y el brillo de la selección se suman.
- Un chip que es un control (un link, un botón activable o una opción de un grupo) tiene el borde en
border-control, que llega a 3:1 contra el fondo como el límite de todo control; en hover sube aborder-control-hover. El chip estático, que no es un control, lo lleva enborder-strong. - La selección no depende del brillo: en colores forzados pasa a
HighlightconHighlightText, y el borde aButtonBorder.
Qué evitar
- Píldoras (radio completo) o corchetes alrededor del texto. El radio de 2 px de los controles de Arche (D11a).
- Una fila de chips activables para elegir una sola opción.
ChipGroupconoptions: unradiogroup, con el teclado de un grupo de radios. - Marcar el tema actual solo con el color. Un link con
current:aria-current="page"y el fondo de la selección. - Chips para acciones («Guardar», «Compartir»).
Button. Un chip nombra un tema o un filtro.