Ir al contenido

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

Svelte
<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.

Svelte
<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.

Svelte
<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
Svelte
<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.

Resumen por correo

Svelte
<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

Props de Segmented
PropDescripció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 falseDeshabilita 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 falseExige 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 radiogroup de Bits UI: cada opción es un <button role="radio"> con aria-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 es border (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 SelectedItem y SelectedItemText: 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 RadioGroup vertical o un Select.
  • 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.