Ir al contenido
Secciones
Idioma, actualmente Español
Sistema de diseño Rastrillo

Presentación

Las piezas pequeñas de vocabulario con las que se arma una pantalla: estado, identidad, progreso y la única forma de aviso.

Cada ejemplo funciona de verdad, pero sus enlaces no llevan a ninguna parte. HTML muestra el marcado para copiar.

status-pill

El estado de un registro como una píldora con color y etiqueta.

Vista previa

neutral

<span rst-status rst-tone="neutral">Borrador</span>

positive

<span rst-status rst-tone="positive">Publicado</span>

warning

<span rst-status rst-tone="warning">Programado</span>

negative

<span rst-status rst-tone="negative">Ha fallado</span>

neutral

{{template "status-pill" dict "Label" "Borrador"}}

positive

{{template "status-pill" dict "Label" "Publicado" "Tone" "positive"}}

warning

{{template "status-pill" dict "Label" "Programado" "Tone" "warning"}}

negative

{{template "status-pill" dict "Label" "Ha fallado" "Tone" "negative"}}

neutral Tone es neutral por defecto, así que esta llamada lo omite.

badge

Una etiqueta con borde en mayúsculas, para marcas pequeñas y fijas. Distinta de status-pill, que es el estado de un registro.

Vista previa

Sin tono (el valor por defecto discreto)

<span rst-badge>Borrador</span>

neutral

<span rst-badge="neutral">Interno</span>

positive

<span rst-badge="positive">En vivo</span>

warning

<span rst-badge="warning">Beta</span>

negative

<span rst-badge="negative">Agotado</span>

Sin tono (el valor por defecto discreto)

{{template "badge" dict "Label" "Borrador"}}

neutral

{{template "badge" dict "Label" "Interno" "Tone" "neutral"}}

positive

{{template "badge" dict "Label" "En vivo" "Tone" "positive"}}

warning

{{template "badge" dict "Label" "Beta" "Tone" "warning"}}

negative

{{template "badge" dict "Label" "Agotado" "Tone" "negative"}}

meter

Una barra de capacidad con su número.

Vista previa

Vacío

<span rst-meter>
  <meter rst-meter-bar value="0" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>0/500</span>
</span>

A medias

<span rst-meter>
  <meter rst-meter-bar value="42" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>210/500</span>
</span>

Casi lleno

<span rst-meter>
  <meter rst-meter-bar value="82" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>412/500</span>
</span>

Lleno

<span rst-meter>
  <meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>500/500</span>
</span>

Por encima del límite

<span rst-meter>
  <meter rst-meter-bar value="100" min="0" max="100" aria-hidden="true"></meter>
  <span rst-meter-num>700/500</span>
</span>

Vacío

{{template "meter" dict "Percent" 0 "Text" "0/500"}}

A medias

{{template "meter" dict "Percent" 42 "Text" "210/500"}}

Casi lleno

{{template "meter" dict "Percent" 82 "Text" "412/500"}}

Lleno

{{template "meter" dict "Percent" 100 "Text" "500/500"}}

Por encima del límite

{{template "meter" dict "Percent" 140 "Text" "700/500"}}

Por encima del límite El relleno se limita al 100% en el parcial.

stat

Un número en un panel, con una etiqueta y cuánto ha cambiado.

El número grande

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat="lead">
  <span rst-stat-label>Ingresos de este mes</span>
  <span rst-stat-num>€48,210</span>
  <span rst-stat-delta rst-tone="positive">&#43;12%</span>
  <span rst-stat-note>frente al mes pasado</span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Ingresos de este mes"
    "Value" "€48,210"
    "Delta" "+12%"
    "Tone" "positive"
    "Note" "frente al mes pasado"
    "Lead" true}}

Añade Lead a una cifra de la fila para hacerla grande. Es el mismo componente, solo que más grande.

Un número más pequeño

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Facturas sin pagar</span>
  <span rst-stat-num>24</span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict "Label" "Facturas sin pagar" "Value" "24"}}

Solo necesitas una etiqueta y un número. Todo lo demás es opcional.

Cuando bajar es bueno

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Tiempo hasta la primera respuesta</span>
  <span rst-stat-num>1 h 12 min</span>
  <span rst-stat-delta rst-tone="positive">−38%</span>
  <span rst-stat-note>frente a la semana pasada</span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Tiempo hasta la primera respuesta"
    "Value" "1 h 12 min"
    "Delta" "−38%"
    "Tone" "positive"
    "Note" "frente a la semana pasada"}}

El color lo decides tú, no el componente. Aquí el número ha bajado y eso es buena noticia, así que el cambio va en verde.

Cuando subir es malo

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Pagos fallidos</span>
  <span rst-stat-num>9</span>
  <span rst-stat-delta rst-tone="negative">&#43;3</span>
  <span rst-stat-note>frente a la semana pasada</span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Pagos fallidos"
    "Value" "9"
    "Delta" "+3"
    "Tone" "negative"
    "Note" "frente a la semana pasada"}}

Aquí el número ha subido y eso es mala noticia, así que el cambio va en rojo.

Cuando no puedes decirlo

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Duración media de la sesión</span>
  <span rst-stat-num>4 min 12 s</span>
  <span rst-stat-delta rst-tone="neutral">&#43;18 s</span>
  <span rst-stat-note>desde el viernes</span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Duración media de la sesión"
    "Value" "4 min 12 s"
    "Delta" "+18 s"
    "Note" "desde el viernes"}}

Omite el color y el cambio se muestra en gris. Hazlo cuando no puedas decir si es bueno o malo.

Un número acortado

Vista previa

Pon esto dentro de <div rst-stats>.

<div rst-stat>
  <span rst-stat-label>Mensajes enviados</span>
  <span rst-stat-num><data value="4120">4.1k</data></span>
</div>

Pon esto dentro de <div rst-stats>.

{{template "stat" dict
    "Label" "Mensajes enviados"
    "Value" "4.1k"
    "Exact" "4120"}}

¿Muestras 4.1k en lugar de 4120? Pon el número completo en Exact. Los lectores de pantalla solo leen lo que está en pantalla, así que deja en el propio número todo lo que una persona necesite.

person

Avatar con iniciales, nombre y correo. Sirve para identificar rápido los registros de personas.

Nombre y correo

Vista previa
<a rst-person href="/people/1">
  <span rst-person-av aria-hidden="true">G</span>
  <span rst-person-meta>
    <span rst-person-name>Grace Hopper</span>
    <span rst-person-email>grace@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/1"
    "Name" "Grace Hopper"
    "Email" "grace@example.com"
    "Initial" "G"}}

Grande, el tamaño de la cabecera de detalle

Vista previa
<a rst-person="lg" href="/people/2">
  <span rst-person-av aria-hidden="true">A</span>
  <span rst-person-meta>
    <span rst-person-name>Ada Lovelace</span>
    <span rst-person-email>ada@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/2"
    "Name" "Ada Lovelace"
    "Email" "ada@example.com"
    "Initial" "A"
    "Large" true}}

Sin inicial

Vista previa
<a rst-person href="/people/3">
  <span rst-person-av="empty" aria-hidden="true"></span>
  <span rst-person-meta>
    <span rst-person-name>Invitación sin aceptar</span>
    <span rst-person-email>invited@example.com</span>
  </span>
</a>
{{template "person" dict
    "Href" "/people/3"
    "Name" "Invitación sin aceptar"
    "Email" "invited@example.com"}}

actor

Quién hizo algo, en palabras: el nombre de una persona, o el agente y la persona por la que actuó. Sin insignia ni icono.

Un agente que actúa por una persona

Vista previa
<span rst-actor>Claude para Grace Hopper</span>
{{template "actor" dict "Actor" .Actor}}

Define ui.ActorName una vez al arrancar para convertir un sujeto en un nombre. La propia aplicación, el Actor cero, no renderiza nada.

Una persona

Vista previa
<span rst-actor>Grace Hopper</span>
{{template "actor" dict "Actor" .Actor}}

callout

El único vocabulario de avisos: franja con color, icono de tono, título en negrita opcional y un párrafo de cuerpo.

info

Vista previa
<div rst-callout rst-tone="info">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
  </span>
  <div rst-callout-body>
    <p>Las entradas solo son visibles para los miembros hasta que se publique el sitio.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Las entradas solo son visibles para los miembros hasta que se publique el sitio."
    "Tone" "info"}}

positive

Vista previa
<div rst-callout rst-tone="positive">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
  </span>
  <div rst-callout-body>
    <strong>Los pagos están conectados</strong>
    <p>Ya puedes cobrar las entradas.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Ya puedes cobrar las entradas."
    "Title" "Los pagos están conectados"
    "Tone" "positive"}}

warning

Vista previa
<div rst-callout rst-tone="warning">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
  </span>
  <div rst-callout-body>
    <strong>Conecta los pagos para empezar a vender</strong>
    <p>Tu evento está publicado, pero aún no puede cobrar.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "Tu evento está publicado, pero aún no puede cobrar."
    "Title" "Conecta los pagos para empezar a vender"
    "Tone" "warning"}}

negative

Vista previa
<div rst-callout rst-tone="negative">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
  </span>
  <div rst-callout-body>
    <strong>La última importación falló</strong>
    <p>No se cambió nada. Corrige la fila 91 y vuelve a intentarlo.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "No se cambió nada. Corrige la fila 91 y vuelve a intentarlo."
    "Title" "La última importación falló"
    "Tone" "negative"}}

negative, anunciado como alerta

Vista previa
<div rst-callout rst-tone="negative" role="alert">
  <span rst-callout-ic aria-hidden="true">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>
  </span>
  <div rst-callout-body>
    <strong>La importación se detuvo</strong>
    <p>No se cambió nada. Corrige la fila 91 y vuelve a intentarlo.</p>
  </div>
</div>
{{template "callout" dict
    "Body" "No se cambió nada. Corrige la fila 91 y vuelve a intentarlo."
    "Title" "La importación se detuvo"
    "Tone" "negative"
    "Alert" true}}

alert añade role="alert" para mostrar mensajes importantes.

detail-list

Lista de definiciones sobre un registro en una pantalla de detalle. La marca mono es para valores de aspecto técnico.

Cuatro datos, uno de aspecto técnico

Vista previa

Pon esto dentro de <section rst-box>.

<dl rst-detail>
  <dt>Público</dt>
  <dd>Miembros</dd>
  <dt>Página principal</dt>
  <dd>No</dd>
  <dt>Publicado</dt>
  <dd>
    <time datetime="2026-08-02">2 de agosto de 2026</time>
  </dd>
  <dt>Referencia</dt>
  <dd class="rst-mono">post_01H9ZQ</dd>
</dl>

Pon esto dentro de <section rst-box>.

{{template "detail-list" dict
    "Items" (list
        (dict "Label" "Público" "Value" "Miembros")
        (dict "Label" "Página principal" "Value" "No")
        (dict "DateTime" "2026-08-02" "Label" "Publicado" "Value" "2 de agosto de 2026")
        (dict "Label" "Referencia" "Mono" true "Value" "post_01H9ZQ"))}}

notice

Una confirmación de una línea después de una redirección. Recibe una cadena simple, no un dict, y no dibuja nada si está vacía.

Un mensaje de guardado

Vista previa
<p rst-notice role="status">Entrada guardada.</p>
{{template "notice" "Entrada guardada."}}

region:notice

El aviso que cada marco mantiene en la página, con el Notice de los datos de la página, para que un lector de pantalla oiga el mensaje y live.js pueda rellenarlo en su sitio.

Un mensaje de guardado

Vista previa
<div id="notice" role="status">
  <p rst-notice>Entrada guardada.</p>
</div>
{{template "region:notice" dict "Notice" "Entrada guardada."}}

form-error

La línea de resumen de errores de un formulario, role="alert". Recibe una cadena simple; no dibuja nada cuando no hay error.

Un envío rechazado

Vista previa
<p rst-form-error role="alert">Ese título ya está en uso.</p>
{{template "form-error" "Ese título ya está en uso."}}

job-status

El fragmento consultado de una tarea en segundo plano. El atributo data-poll solo se emite mientras la tarea se ejecuta: omitirlo es la forma de detener el sondeo.

En marcha

Vista previa

<div rst-job data-poll="/jobs/1/fragment" data-poll-every="2">
  <span rst-spin aria-hidden="true"></span> <bdi><strong>Importación</strong></bdi> en curso: <bdi>128 de 400</bdi>…
  <progress rst-job-bar value="32" min="0" max="100" aria-hidden="true"></progress>
</div>
{{template "job-status" dict
    "Name" "Importación"
    "Percent" 32
    "PollSeconds" 2
    "PollURL" "/jobs/1/fragment"
    "Progress" "128 de 400"
    "Status" "running"}}

Este hace sondeo: es la única muestra de la página que le pide algo a la red y, en un sitio estático, sencillamente nunca se resuelve.

Terminado

Vista previa

<div rst-job>
  <bdi><strong>Importación</strong></bdi> ha terminado.
</div>
{{template "job-status" dict "Name" "Importación" "Status" "done"}}

Ha fallado

Vista previa

<div rst-job>
  <bdi><strong>Importación</strong></bdi> ha fallado: <bdi>row 91: no such column &#34;published&#34;</bdi>
</div>
{{template "job-status" dict
    "Err" "row 91: no such column \"published\""
    "Name" "Importación"
    "Status" "failed"}}