Saltar al contenido

Grupo de alternancia

Grupos de botones de dos estados para barras de herramientas de editor, selectores de vista y barras de filtro, con el estilo neobrutalista de bordes y sombras.

import { Bold, Italic, Underline } from "lucide-react"

import {

El grupo de conmutadores es una fila de botones de dos estados en la que puede haber uno (el comportamiento por defecto) o varios (multiple) pulsados a la vez. Está construido sobre el componente Base UI Toggle Group y sigue la receta neobrutalista: bordes gruesos, sombras marcadas y tipografía en negrita.

Recurre a este componente cuando:

  • Barras de herramientas de editor — negrita/cursiva/subrayado, alineación del texto, estilos de lista con multiple.
  • Conmutadores de vista — cuadrícula o lista, gráfico o tabla, día/semana/mes; el modo por defecto mantiene como mucho uno activo.
  • Barras de filtros — etiquetas, categorías o facetas que el usuario puede ir activando y desactivando.

Instalación

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/toggle-group.json
npx shadcn@latest add https://neobrutalism.com/r/base/toggle-group.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/toggle-group.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/toggle-group.json

Instala las siguientes dependencias:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

Copia y pega el siguiente código en tu proyecto.

components/ui/toggle-group.tsx
"use client"

import * as React from "react"
import { type VariantProps } from "class-variance-authority"
import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui"

import { cn } from "@/lib/utils"
import { toggleVariants } from "@/components/ui/toggle"

const ToggleGroupContext = React.createContext<
  VariantProps<typeof toggleVariants> & {
    spacing?: number
    orientation?: "horizontal" | "vertical"
  }
>({
  size: "default",
  variant: "default",
  spacing: 2,
  orientation: "horizontal",
})

function ToggleGroup({
  className,
  variant,
  size,
  spacing = 2,
  orientation = "horizontal",
  children,
  ...props
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
  VariantProps<typeof toggleVariants> & {
    spacing?: number
    orientation?: "horizontal" | "vertical"
  }) {
  return (
    <ToggleGroupPrimitive.Root
      data-slot="toggle-group"
      data-variant={variant}
      data-size={size}
      data-spacing={spacing}
      data-orientation={orientation}
      style={{ "--gap": spacing } as React.CSSProperties}
      className={cn(
        "group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-vertical:flex-col data-vertical:items-stretch",
        className
      )}
      {...props}
    >
      <ToggleGroupContext.Provider
        value={{ variant, size, spacing, orientation }}
      >
        {children}
      </ToggleGroupContext.Provider>
    </ToggleGroupPrimitive.Root>
  )
}

function ToggleGroupItem({
  className,
  children,
  variant = "default",
  size = "default",
  ...props
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
  VariantProps<typeof toggleVariants>) {
  const context = React.useContext(ToggleGroupContext)

  return (
    <ToggleGroupPrimitive.Item
      data-slot="toggle-group-item"
      data-variant={context.variant || variant}
      data-size={context.size || size}
      data-spacing={context.spacing}
      className={cn(
        "shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t",
        toggleVariants({
          variant: context.variant || variant,
          size: context.size || size,
        }),
        className
      )}
      {...props}
    >
      {children}
    </ToggleGroupPrimitive.Item>
  )
}

export { ToggleGroup, ToggleGroupItem }

Ajusta las rutas de importación a la configuración de tu proyecto.

Uso

import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
<ToggleGroup type="single">
  <ToggleGroupItem value="a">A</ToggleGroupItem>
  <ToggleGroupItem value="b">B</ToggleGroupItem>
  <ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>

Composición

Usa la siguiente composición para construir un ToggleGroup:

ToggleGroup
├── ToggleGroupItem
└── ToggleGroupItem

Ejemplos

Outline

Usa variant="outline" para un estilo con contorno.

import {
  ToggleGroup,
  ToggleGroupItem,

Tamaño

Usa la prop size para cambiar el tamaño del grupo de botones.

import {
  ToggleGroup,
  ToggleGroupItem,

Espaciado

Usa spacing para añadir espacio entre los elementos del grupo.

import {
  ToggleGroup,
  ToggleGroupItem,

Vertical

Usa orientation="vertical" para grupos verticales.

import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react"

import {

Deshabilitado

import { Bold, Italic, Underline } from "lucide-react"

import {

Personalizado

Un ejemplo de grupo de botones personalizado.

"use client"

import * as React from "react"

RTL

Para activar el soporte RTL en Neobrutalism, consulta la guía de configuración de RTL.

"use client"

import * as React from "react"

Accesibilidad

Cada elemento es un botón conmutador según el patrón Button de WAI-ARIA: el grupo renderiza role="group" y cada elemento es un <button> real con aria-pressed, tanto en modo único como múltiple. El foco usa un tabindex itinerante (roving tabindex), así que todo el grupo es una única parada de tabulación. Los elementos de solo icono necesitan un aria-label.

Interacciones de teclado:

TeclaAcción
Tab / Shift + TabLleva el foco al grupo y lo saca de él
Space / EnterAlterna el elemento con foco
ArrowRight / ArrowDownMueve el foco al siguiente elemento
ArrowLeft / ArrowUpMueve el foco al elemento anterior
Home / EndSalta al primer / último elemento

Referencia de API

Consulta la documentación de Base UI Toggle Group.

Registro de cambios

2026-05-17 Espaciado predeterminado

El valor predeterminado de spacing cambia de 0 a 2, de modo que los grupos ahora se muestran con espacio entre los elementos por defecto. Usa spacing={0} para elementos contiguos.