Ir al contenido

Componentes · Ola 4 · Editorial

Index list

Una lista de filas que llevan cada una a su página: el archivo por año, los resultados de una búsqueda, el índice de temas o las sugerencias de una página de error. Toda la fila es un link. La fecha y el dato van en IBM Plex Mono de 12 px, en minúsculas y con 0,08 em de tracking. Se reacomoda con el ancho de la lista: por debajo de 520 px, la fecha y el dato bajan debajo del título.

import { IndexList, IndexListItem } from '@archeblack/ui';

Ejemplos

Archivo por año

El año grande de SectionHeader y, debajo, una fila por post: la fecha sin año, el título en 15 px y el tiempo de lectura. Pasa el puntero: la línea de la fila se enciende.

2026

Svelte
<script lang="ts">
	import { IndexList, IndexListItem, SectionHeader } from '@archeblack/ui';

	// El archivo de Hermes en 2026, del más reciente al más antiguo.
	const posts = [
		{
			title: 'El Alma Pide Locura',
			slug: 'el-alma-pide-locura',
			date: '2026-07-27T21:45:16Z',
			minutes: 15
		},
		{
			title: 'Lo que cambia cuando alguien escucha',
			slug: 'lo-que-cambia-cuando-alguien-escucha',
			date: '2026-05-03T01:33:44Z',
			minutes: 15
		},
		{
			title: 'El Daimon en la Máquina',
			slug: 'el-daimon-en-la-maquina',
			date: '2026-01-28T12:00:00Z',
			minutes: 11
		},
		{
			title: 'El Doctor que Bailó con el Tiempo',
			slug: 'el-doctor-que-bailo-con-el-tiempo',
			date: '2026-01-17T12:00:00Z',
			minutes: 9
		},
		{
			title: 'Lo Numinoso en CONTROL',
			slug: 'lo-numinoso-en-control',
			date: '2026-01-04T12:00:00Z',
			minutes: 10
		}
	];
</script>

<!-- El archivo por año (D11c): el año grande (SectionHeader size="lg") pone la regla de arriba y
     cada fila lleva la fecha sin el año, el título y el tiempo de lectura. Toda la fila es un link.
     metaLabel dice cómo se lee el dato: «15 minutos de lectura».
     En una página real el año es un h2; aquí es h4 porque vive en la documentación. -->
<section aria-labelledby="archive-2026" style="width: 100%">
	<SectionHeader level={4} size="lg" title="2026" titleId="archive-2026" />
	<IndexList>
		{#each posts as post (post.slug)}
			<IndexListItem
				title={post.title}
				href={`#${post.slug}`}
				date={post.date}
				meta={`${post.minutes} min`}
				metaLabel={`${post.minutes} minutos de lectura`}
			/>
		{/each}
	</IndexList>
</section>

Con número

Con ordinal, la lista suma una columna de 3rem al inicio (2,5rem en angosto). Apagado por defecto.

Svelte
<script lang="ts">
	import { IndexList, IndexListItem } from '@archeblack/ui';

	// Los cuatro posts más recientes de Hermes, numerados en el orden en que se publicaron.
	const posts = [
		{ title: 'El Alma Pide Locura', slug: 'el-alma-pide-locura', date: '2026-07-27T21:45:16Z' },
		{
			title: 'Lo que cambia cuando alguien escucha',
			slug: 'lo-que-cambia-cuando-alguien-escucha',
			date: '2026-05-03T01:33:44Z'
		},
		{
			title: 'El Daimon en la Máquina',
			slug: 'el-daimon-en-la-maquina',
			date: '2026-01-28T12:00:00Z'
		},
		{
			title: 'El Doctor que Bailó con el Tiempo',
			slug: 'el-doctor-que-bailo-con-el-tiempo',
			date: '2026-01-17T12:00:00Z'
		}
	];
</script>

<!-- Con número: basta que una fila lleve ordinal para que la lista reserve la columna. Es un dato
     chico, en la mono de los datos, nunca una cifra grande. Aquí la fecha lleva el año. -->
<IndexList aria-label="Publicaciones recientes" style="width: 100%">
	{#each posts as post, index (post.slug)}
		<IndexListItem
			ordinal={`#${posts.length + 1 - index}`}
			title={post.title}
			href={`#${post.slug}`}
			date={post.date}
			year
		/>
	{/each}
</IndexList>

Resultados de búsqueda

variant="listing" con Highlight en el título y el fragmento, en Hermes. El resaltado hereda el peso: 600 en el título y 400 en el fragmento.

2 resultados para «alma»

  • El Alma Pide Locura Hay caminos fuera del jardín. Sobre la sed que el saber no calma, y la disposición que el alma estaba pidiendo.
  • El Doctor que Bailó con el Tiempo Por qué el Undécimo Doctor elige el juego después de novecientos años de peso. La ligereza como pedagogía del alma, no como evasión.
Svelte
<script lang="ts">
	import '@archeblack/ui/products/hermes.css';
	import { Highlight, IndexList, IndexListItem } from '@archeblack/ui';

	const query = 'alma';

	// Los dos posts de Hermes que coinciden con «alma», con su bajada como fragmento.
	const results = [
		{
			title: 'El Alma Pide Locura',
			slug: 'el-alma-pide-locura',
			dek: 'Hay caminos fuera del jardín. Sobre la sed que el saber no calma, y la disposición que el alma estaba pidiendo.'
		},
		{
			title: 'El Doctor que Bailó con el Tiempo',
			slug: 'el-doctor-que-bailo-con-el-tiempo',
			dek: 'Por qué el Undécimo Doctor elige el juego después de novecientos años de peso. La ligereza como pedagogía del alma, no como evasión.'
		}
	];
</script>

<!-- Resultados de búsqueda: variant="listing", con el título en 17 px y el fragmento en Piazzolla.
     Highlight marca las coincidencias con el fondo de la selección (D8b), en el acento de Hermes.
     Busca subcadenas: «alma» también marca el «alma» de «calma». -->
<div data-product="hermes" style="display: grid; gap: var(--arche-spacing-3); width: 100%">
	<p
		id="results-count"
		style="margin: 0; font: var(--arche-typography-label); letter-spacing: var(--arche-typography-label-letter-spacing); text-transform: uppercase; color: var(--arche-color-text-subtle)"
	>
		2 resultados para «{query}»
	</p>
	<IndexList variant="listing" aria-labelledby="results-count">
		{#each results as result (result.slug)}
			<IndexListItem href={`#${result.slug}`}>
				{#snippet title()}<Highlight text={result.title} {query} />{/snippet}
				{#snippet description()}<Highlight text={result.dek} {query} />{/snippet}
			</IndexListItem>
		{/each}
	</IndexList>
</div>

Índice de temas

Los temas con su conteo al final, en la mono de los datos.

Svelte
<script lang="ts">
	import { IndexList, IndexListItem } from '@archeblack/ui';

	// Los cuatro temas de Hermes, con la cantidad de artículos de cada uno.
	const topics = [
		{ name: 'Filosofía', slug: 'filosofia', count: 4 },
		{ name: 'Cultura', slug: 'cultura', count: 3 },
		{ name: 'Videojuegos', slug: 'videojuegos', count: 2 },
		{ name: 'Tecnología', slug: 'tecnologia', count: 1 }
	];
</script>

<!-- El índice de temas: el nombre y, al final, el conteo en la mono de los datos. -->
<IndexList variant="listing" aria-label="Temas" style="width: 100%">
	{#each topics as topic (topic.slug)}
		<IndexListItem
			title={topic.name}
			href={`#${topic.slug}`}
			meta={topic.count === 1 ? '1 artículo' : `${topic.count} artículos`}
		/>
	{/each}
</IndexList>

Sugerencias de una página de error

La misma fila, sin fecha, con una aclaración al final.

Quizás buscabas

Svelte
<script lang="ts">
	import { Eyebrow, IndexList, IndexListItem } from '@archeblack/ui';
</script>

<!-- Las sugerencias de una página de error: la misma fila del listado, sin fecha, con una
     aclaración al final. Nada de cifras grandes dentro de la lista. -->
<div style="display: grid; gap: var(--arche-spacing-3); width: 100%">
	<Eyebrow id="not-found-suggestions" topic="Quizás buscabas" />
	<IndexList variant="listing" aria-labelledby="not-found-suggestions">
		<IndexListItem title="Todas las publicaciones" href="#publicaciones" meta="Archivo completo" />
		<IndexListItem title="Temas" href="#temas" meta="Temas editoriales" />
	</IndexList>
</div>

Props

IndexList

Props de IndexList
PropDescripción
variant? 'archive' | 'listing' Por defecto 'archive'archive: filas de columnas (número, fecha, título y dato), título en 15 px, 14 px de relleno y una línea de border-subtle debajo. listing: título en 17 px con descripción en Piazzolla, el dato al final, 16 px de relleno y una línea de border arriba. Para resultados de búsqueda, temas y sugerencias.
children? Snippet Las filas: un IndexListItem cada una.
class? ClassValue Se suma a arche-index-list.
...rest HTMLAttributes Van al <ul>: un nombre con aria-label o aria-labelledby.

IndexListItem

Props de IndexListItem
PropDescripción
title string | Snippet El título. Con href, es el texto del link. Como snippet, para marcar coincidencias con Highlight.
href? string Destino de la fila. El link es el título y se estira sobre toda la fila. Sin href, la fila es texto.
ordinal? string | number El número de orden («#5»), tal cual, en la primera columna. Sin ninguno en la lista, la columna no existe.
date? Date | string La fecha, en un <time>: «27 jul», en minúsculas.
year? boolean Por defecto falseSuma el año a la fecha («27 jul 2026»). En el archivo por año, el año ya está en el separador.
locale? string Por defecto 'es'Idioma de la fecha.
timeZone? string Por defecto 'UTC'Zona horaria de la fecha: la misma en el servidor y en el navegador.
description? string | Snippet Debajo del título, en Piazzolla de 15 px y text-muted: la bajada de un tema o el fragmento de un resultado.
meta? string | number | Snippet El dato al final: el tiempo de lectura («15 min»), un conteo («4 artículos») o una aclaración.
metaLabel? string Cómo se lee el dato («15 minutos de lectura»). El lector de pantalla oye este texto en lugar del dato visible.
class? ClassValue Se suma a arche-index-list__item.
...rest HTMLAttributes Van al <li>.

Accesibilidad

  • Es una lista real (<ul role="list"> con un <li> por fila): el lector de pantalla anuncia cuántas filas hay. role porque Safari quita la semántica a una lista sin viñetas.
  • Cada fila tiene un solo link, el título, estirado sobre la fila con un ::after: toda la fila responde al puntero y el teclado pasa una sola vez por fila. Sin links anidados; otro link dentro de la fila queda por encima y sigue siendo su propio destino.
  • La fecha va en un <time datetime>. Con metaLabel, el dato visible es aria-hidden y el lector oye el texto completo («15 minutos de lectura»).
  • El foco es el anillo de Arche sobre el título y, además, la línea de la fila se enciende, como con el puntero.
  • Por debajo de 520 px de lista, la fecha y el dato bajan debajo del título en lugar de ocultarse: la misma información en el teléfono. Es una consulta de contenedor: responde al ancho de la lista, no al de la ventana.
  • En colores forzados, las líneas toman el color del texto del sistema y, en hover o con foco, el de la selección.

Qué evitar

  • Un link en el título y otro envolviendo la fila. Solo href: el título ya se estira sobre la fila.
  • Ocultar la fecha y el tiempo de lectura en el teléfono. Dejar que bajen debajo del título, como hace la lista.
  • Un número grande o una cifra destacada dentro de la lista. El número chico, en la mono de los datos (ordinal), o ninguno (D2 y D11b).
  • Repetir el año en cada fila del archivo por año. El año en el separador (SectionHeader size="lg") y la fecha sin año.
  • Marcar las coincidencias de una búsqueda con {@html}. Highlight dentro de los snippets title y description.