Componentes · Ola 2 · Formularios
Segmented
Grupo de opciones excluyentes en una fila, para cambiar un ajuste o una vista. La opción elegida sube a la capa más clara con un aro del color de selección. Es un grupo de radios: una sola parada del tabulador y las flechas mueven la selección.
import { Segmented } from '@archeblack/ui';
Ejemplos
Grupo
label pone el texto visible y nombra al grupo; bind:value sigue la opción elegida.
Plan
Plan elegido: studio
<script lang="ts">
import { Segmented } from '@archeblack/ui';
let plan = $state('studio');
</script>
<div style:display="grid" style:justify-items="center" style:gap="var(--arche-spacing-3)">
<Segmented
label="Plan"
bind:value={plan}
options={[
{ value: 'free', label: 'Gratis' },
{ value: 'studio', label: 'Estudio' },
{ value: 'team', label: 'Equipo' }
]}
/>
<p style:margin="0" style:color="var(--arche-color-text-muted)">
Plan elegido: <code>{plan}</code>
</p>
</div> Tallas
sm, md (por defecto) y lg, con los altos de Button. Sin texto visible, el grupo se nombra con aria-label.
<script lang="ts">
import { Segmented } from '@archeblack/ui';
const options = [
{ value: '2', label: '2 px' },
{ value: '3', label: '3 px' },
{ value: '4', label: '4 px' }
];
let small = $state('2');
let medium = $state('2');
let large = $state('2');
</script>
<!-- Los mismos altos que Button: 28, 36 y 44 px. -->
<div style:display="grid" style:justify-items="center" style:gap="var(--arche-spacing-4)">
<Segmented aria-label="Radio base, talla sm" size="sm" {options} bind:value={small} />
<Segmented aria-label="Radio base, talla md" {options} bind:value={medium} />
<Segmented aria-label="Radio base, talla lg" size="lg" {options} bind:value={large} />
</div> Con íconos
Cada opción acepta un icon decorativo antes del texto.
<script lang="ts">
import { Segmented } from '@archeblack/ui';
import { IconLayoutGrid, IconLayoutList } from '@archeblack/ui/icons';
let view = $state('grid');
</script>
<!-- El ícono es decorativo: el texto de cada opción sigue siendo su nombre. -->
<Segmented
aria-label="Vista de los proyectos"
bind:value={view}
options={[
{ value: 'grid', label: 'Grilla', icon: IconLayoutGrid },
{ value: 'list', label: 'Lista', icon: IconLayoutList }
]}
/> Deshabilitado
disabled en una opción la apaga y las flechas la saltan; en el grupo, lo apaga entero.
Región
Facturación
<script lang="ts">
import { Segmented } from '@archeblack/ui';
let region = $state('us');
let billing = $state('monthly');
</script>
<div style:display="grid" style:justify-items="start" style:gap="var(--arche-spacing-5)">
<!-- Una opción deshabilitada: las flechas la saltan. -->
<Segmented
label="Región"
bind:value={region}
options={[
{ value: 'us', label: 'Estados Unidos' },
{ value: 'eu', label: 'Europa' },
{ value: 'sa', label: 'Sudamérica', disabled: true }
]}
/>
<!-- Todo el grupo deshabilitado. -->
<Segmented
label="Facturación"
disabled
bind:value={billing}
options={[
{ value: 'monthly', label: 'Mensual' },
{ value: 'yearly', label: 'Anual' }
]}
/>
</div> En un formulario
Con name, el grupo envía el valor elegido como cualquier campo.
<script lang="ts">
import { Button, Segmented } from '@archeblack/ui';
let sent = $state('');
function submit(event: SubmitEvent) {
event.preventDefault();
const data = new FormData(event.currentTarget as HTMLFormElement);
sent = String(data.get('frequency'));
}
</script>
<!-- Con name, el grupo envía la opción elegida como cualquier campo. -->
<form
onsubmit={submit}
style:display="grid"
style:justify-items="start"
style:gap="var(--arche-spacing-4)"
>
<Segmented
label="Resumen por correo"
name="frequency"
value="weekly"
options={[
{ value: 'daily', label: 'Diario' },
{ value: 'weekly', label: 'Semanal' },
{ value: 'never', label: 'Nunca' }
]}
/>
<Button type="submit" size="sm">Guardar</Button>
<p role="status" style:margin="0" style:color="var(--arche-color-text-muted)">
{sent ? `Se envió frequency=${sent}` : ''}
</p>
</form> Props
| Prop | Descripción |
|---|---|
options SegmentedOption[] | Las opciones, en orden: { value, label, icon?, disabled? }. El label es el texto visible y el nombre de la opción; el icon es decorativo. |
bind:value? string | Valor de la opción elegida; undefined si ninguna. Con un bind:value de función el producto puede rechazar el cambio: la opción anterior sigue elegida. |
onValueChange? (value: string) => void | Se llama cuando la persona elige otra opción, con el valor nuevo, después de actualizar value y solo si el cambio se aceptó (un bind:value de función puede rechazarlo). |
label? string | Texto visible encima del grupo, con el aspecto de la etiqueta de Field. Nombra al grupo con aria-labelledby. |
aria-label? string | Nombre del grupo cuando no hay texto visible; si otro texto de la página ya lo nombra, aria-labelledby con su id. Hace falta uno de label, aria-label o aria-labelledby: TypeScript rechaza un grupo sin nombre. |
size? 'sm' | 'md' | 'lg' Por defecto 'md' | Alto exterior de 28, 36 o 44 px, los mismos de Button. Va en data-size de la raíz. |
disabled? boolean Por defecto false | Deshabilita todo el grupo. Para una sola opción, disabled en la opción. |
name? string | Nombre del campo en el formulario: el grupo pone un input oculto con el valor elegido. Sin name no se envía. |
required? boolean Por defecto false | Exige elegir una opción antes de enviar (requiere name). Pone aria-required en el grupo. |
class? ClassValue | Clases del producto; se suman a arche-segmented, el contenedor. |
...rest HTMLAttributes<HTMLDivElement> | Todo lo demás (id, aria-describedby, data-*) va al grupo, el elemento con role="radiogroup". |
Accesibilidad
- Es un
radiogroupde Bits UI: cada opción es un<button role="radio">conaria-checked. Los lectores de pantalla anuncian el nombre del grupo, la opción y su posición («2 de 3»). - El grupo es una sola parada del tabulador: el foco entra en la opción elegida. Las flechas (las cuatro) mueven el foco y la selección, dan la vuelta al llegar al final y saltan las opciones deshabilitadas; Inicio y Fin van a la primera y a la última; Espacio elige.
- El foco es el de Arche y se dibuja sobre la opción visible; en la opción elegida, el halo se suma al aro de selección.
- El aro de la opción elegida es el color de selección y llega a 3:1 contra todas las capas; además cambia de fondo y su texto pasa a
text-strong. El borde del grupo esborder(15 %), como el demo: es un contenedor y no dice el estado, y cada opción se reconoce por su texto. - En colores forzados la opción elegida usa
SelectedItemySelectedItemText: el estado no depende de un fondo que el navegador reemplaza. - El texto de cada opción es su nombre; el ícono es decorativo. Sin texto visible del grupo, pon
aria-label.
Qué evitar
- Más de cuatro o cinco opciones, o textos largos que no entran en una fila en un móvil. Un
RadioGroupvertical o unSelect. - Un segmented para navegar entre secciones con contenido propio.
Tabs, que conecta cada pestaña con su panel. - Opciones que se pueden combinar. Casillas (
Checkbox) o botones de alternar independientes. - Opciones solo con íconos. Un texto corto en cada opción; el ícono lo acompaña.
- Un grupo sin opción elegida cuando una es la habitual. Empieza con esa opción en
value.