Number field
Campo numérico · components/fields/number-field
Un número acotado con un botón − y uno + a los costados. Los dígitos giran como un cuentakilómetros cada vez que cambia el valor; mantener apretado repite y acelera; al llegar al máximo (o al mínimo) el número se tensa hacia el botón y vuelve, el botón se sacude una vez y aparece al lado de la etiqueta una nota naranja que dice el tope ("Máx. 10 licencias"). La descripción de abajo puede llevar el precio: las palabras que cambian suben y se enfocan, el resto se queda quieto. Se puede tipear directo, mover con las flechas y, con scrub, arrastrar la etiqueta. Viene con AnimatedCounter, un contador grande para mostrar el total al lado.
Por qué entró
La dinámica: la alerta cuando llegás al máximo y cómo te va sumando el precio a medida que agregás.
Sirve para
- agregar personas o licencias a un equipo
- cantidades con precio total
- cupos, invitados o puestos con un tope claro
No sirve para
- un valor aproximado donde importa más la posición que el número exacto: ahí va un slider
- códigos, documentos o teléfonos: son texto, no cantidades
Origen: Arc UI, porteado a nuestro stack y traducido. La licencia del sitio no está declarada: se usa en nuestras apps, no se publica.
Cómo se usa
import { NumberField } from '@/components/ui/number-field/NumberField'
import { AnimatedCounter } from '@/components/ui/number-field/AnimatedCounter'
<NumberField label="Licencias" value={cantidad} onValueChange={setCantidad} min={1} max={10} suffix={n => n === 1 ? ' licencia' : ' licencias'} description={`$ ${precio} por licencia al mes`} />
<AnimatedCounter value={cantidad * precio} prefix="$ " />
<NumberField label="Precio" defaultValue={12.5} step={0.5} prefix="$ " size="lg" />
<NumberField label="Invitados" max={3} limitHint={(borde, tope) => borde === 'max' ? `Hasta ${tope}` : `Mínimo ${tope}`} />
value/defaultValue/onValueChange(valor): controlado o no. Siempre sale un número dentro deminymax(por defecto 0 y sin tope) y en la grilla destep(1).largeStep: lo que se mueven RePág, AvPág y Shift + flecha. Por defecto diez pasos.prefix/suffix: texto pegado al número, fijo o una función del valor para que concuerde (' licencia'/' licencias').description: la línea de abajo. Si ponés el total ahí, el número cambia con movimiento.limitHint: la nota junto a la etiqueta al tocar un límite.true(por defecto) escribe "Máx. …" / "Mín. …", una función escribe lo que quieras,falsela saca.scrub: arrastrar la etiqueta a los costados cambia el valor; pasado el límite resiste y vuelve.size:sm,md(por defecto) olg;widthen píxeles si el ancho por defecto no va.locale(es-AR) yformatOptionspara decimales y separador de miles.- Teclado: flechas (mantener repite), RePág/AvPág, Inicio/Fin a los límites, Enter
confirma lo tipeado, Escape lo descarta. Es un
spinbuttonpara el lector de pantalla. AnimatedCounter:value,prefix,suffix,decimals,label,locale,animateOnView(gira desde cero al entrar en pantalla) yclassNamepara el tamaño.- Con
prefers-reduced-motiontodo cambia sin viaje: los dígitos se funden y al tocar un límite el número sólo cambia de color un instante.
Qué toma de tu app
Fondo, bordes, textos, el radio del control y los botones salen de los tokens --ui-*. La
nota del límite y el borde cuando tipeás un valor fuera de rango son naranja de aviso:
semántico, no cambia de app, del acento toma sólo la luz y la saturación. El contador usa
--ui-font-display. Las duraciones y los resortes salen de --ui-dur y --ui-ease.
Necesita motion y lucide-react.
Details
- Source
- Arc UI · Not declared
- Added
- October 2, 2026 · francovassallo
- Tags
- numerocantidadpreciomaximostepperlicencias
- Tokens used
--ui-dur--ui-font-display--ui-ink--ui-font-text--ui-ink-muted--ui-radius-lg--ui-line--ui-surface--ui-accent--ui-radius--ui-ink-soft--ui-ease--ui-surface-2- Dependencies
lucide-reactmotion- Used in
- Not in any app yet