Input Group
Un campo con cosas pegadas adentro —«$», «.com», la lupa, un ⌘K o un botón—, con la superficie y el foco de iCloud en el grupo.
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "sebs7n-ui/input-group"Ejemplos
Antes y después del valor
La moneda, el dominio o la lupa van adentro del campo: la superficie y el foco son del grupo, y un click en el texto enfoca el campo.
import { InputGroup, InputGroupAddon, InputGroupInput } from "sebs7n-ui/input-group"
import { Kbd } from "sebs7n-ui"
import { SearchIcon } from "lucide-react"
function Basico() {
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<InputGroup>
<InputGroupAddon>$</InputGroupAddon>
<InputGroupInput aria-label="Importe" inputMode="decimal" placeholder="0,00" />
<InputGroupAddon>ARS</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupAddon>facturas.</InputGroupAddon>
<InputGroupInput aria-label="Subdominio" placeholder="tu-empresa" />
<InputGroupAddon>.com</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupInput aria-label="Buscar comprobantes" placeholder="Buscar comprobantes" type="search" />
<InputGroupAddon>
<Kbd size="sm">⌘K</Kbd>
</InputGroupAddon>
</InputGroup>
</div>
)
}Con un botón
Un botón a escala del campo: `plain` para la acción, `ghost` para uno de ícono (con `aria-label`).
import { CopyIcon } from "lucide-react"
import { Field, FieldLabel } from "sebs7n-ui"
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "sebs7n-ui/input-group"
function ConBoton() {
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<Field>
<FieldLabel>Cupón de descuento</FieldLabel>
<InputGroup>
<InputGroupInput placeholder="VERANO26" />
<InputGroupAddon>
<InputGroupButton variant="plain">Aplicar</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</Field>
<InputGroup>
<InputGroupInput aria-label="Link de pago" readOnly value="https://pagos.example.com/f/0012" />
<InputGroupAddon>
<InputGroupButton aria-label="Copiar el link">
<CopyIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
)
}Tamaños
28, 36 y 40, los mismos altos que los botones: un campo y un botón del mismo `size` miden lo mismo.
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "sebs7n-ui/input-group"
function Tamanos() {
return (
<div className="flex w-full max-w-sm flex-col gap-4">
{(["sm", "md", "lg"] as const).map((size) => (
<InputGroup key={size} size={size}>
<InputGroupAddon>$</InputGroupAddon>
<InputGroupInput aria-label={`Importe ${size}`} placeholder="0,00" />
<InputGroupAddon>
<InputGroupButton variant="plain">Cobrar</InputGroupButton>
</InputGroupAddon>
</InputGroup>
))}
</div>
)
}Botón esperando
`loading` en `InputGroupButton`: el spinner en el lugar del texto, el ancho no salta y el clic no pasa.
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "sebs7n-ui/input-group"
import { TicketIcon } from "lucide-react"
import { useState } from "react"
function Cargando() {
const [loading, setLoading] = useState(false)
return (
<div className="w-full max-w-sm">
<InputGroup>
<InputGroupAddon>
<TicketIcon />
</InputGroupAddon>
<InputGroupInput aria-label="Cupón" defaultValue="BIENVENIDA" />
<InputGroupAddon>
<InputGroupButton
loading={loading}
onClick={() => {
setLoading(true)
setTimeout(() => setLoading(false), 1500)
}}
variant="plain"
>
Aplicar
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
)
}Props
Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».
InputGroup
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
disabled | boolean | — | Apaga el campo, los botones de adentro y la superficie (a .4). |
size | "sm" | "md" | "lg" | "md" | sm 28, md 36 (default), lg 40. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
InputGroupAddon
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
onMouseDown | MouseEventHandler<T> | — | Se llama antes de enfocar el campo. Con event.preventDefault(), el click no lo enfoca. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
InputGroupButton
Hereda las props de Button.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
disabled | boolean | — | Apaga la interacción y lo marca con data-disabled, que es el atributo del que cuelgan los estilos de apagado. |
loading | boolean | false | Esperando (validando el cupón, buscando): como Button, el spinner en el lugar del contenido (el ancho no salta), aria-busy y el clic no pasa. |
onClick | MouseEventHandler<T> | — | Se ignora mientras loading está activo. |
variant | "default" | "plain" | "ghost" | "ghost" | ghost (default, neutro), plain (texto en el acento) o default (acento sólido). |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
InputGroupInput
Hereda las props de Input.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
disabled | boolean | — | Apaga la interacción y lo marca con data-disabled, que es el atributo del que cuelgan los estilos de apagado. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
Teclado
- Tab
- Entra al campo y sigue a los botones de adentro, en el orden en que están.
Accesibilidad
- El nombre es el del campo:
FieldLabelen unField, oaria-labelenInputGroupInput. Un addon de texto («$», «.com») no lo nombra: si hace falta que se lea, ponelo en el label («Importe en pesos»). - Los íconos de un addon son decorativos; un
InputGroupButtonde solo ícono necesitaaria-label. - El foco se ve en el grupo (el anillo interior de 3 px, sin relleno) aunque lo tenga el
<input>de adentro; el inválido (aria-invaliden el input) pone el borde rojo al grupo. - Un click en un addon de texto o ícono enfoca el campo; en un botón, hace lo del botón.
Reglas de uso
- Para un dato con unidad o formato fijo (moneda, dominio, prefijo) o una acción que es del campo (copiar, aplicar un cupón). Una acción de todo el formulario va afuera, en un
Button. - Los addons van en el orden del DOM: antes del
InputGroupInputquedan a la izquierda, después a la derecha. size28/36/40 como los botones; el botón de adentro escala solo (20/28/32).InputGroupButton loading: comoButton, el spinner en el lugar del contenido (el ancho no salta),aria-busyy el clic no pasa. Para «Aplicar» un cupón mientras se valida.- Para buscar con sugerencias es
ComboboxoAutocomplete, que ya usan esta misma superficie. - Solo por subpath (
sebs7n-ui/input-group): no está en el barrel, por peso.