Moodinary/UI

Input group

Cuando el valor tiene prefijo, sufijo o acción pegada (URL, copiar, buscar).

Campos compuestos del dashboard: PrefixedInput para la pantalla pública, SearchInput para buscar por idea y CopyField para el código corto de acceso. SuffixInput es una variante disponible sin uso actual en la app.

Instalación

shadcn
npx shadcn@latest add https://design.moodinary.com/r/input-group.json
import
import { PrefixedInput, SearchInput, CopyField, SuffixInput } from "@moodinary/ui/components/input-group";

Ejemplos

Prefijo, búsqueda, copiar y unidad

El prefijo es fijo. CopyField muestra un valor de solo lectura; tu callback decide cómo copiarlo y cuándo confirmar el resultado.

/kiosk/

Código ilustrativo, no es un acceso real.

%
Código
default.tsx
"use client";

import { Field, FieldHint, FieldLabel } from "@moodinary/ui/components/field";
import {
	CopyField,
	PrefixedInput,
	SearchInput,
	SuffixInput,
} from "@moodinary/ui/components/input-group";
import { useCallback, useState } from "react";

function copyHint(copyError: boolean, copied: boolean): string {
	if (copyError) {
		return "No se pudo copiar. Seleccioná el código y copialo a mano.";
	}
	return copied
		? "Link de ejemplo copiado."
		: "Código ilustrativo, no es un acceso real.";
}

export default function InputGroupDefault() {
	const [copied, setCopied] = useState(false);
	const [copyError, setCopyError] = useState(false);
	const copy = useCallback(async () => {
		setCopyError(false);
		try {
			await navigator.clipboard.writeText("https://send.moodinary.com/ABC123");
			setCopied(true);
			setTimeout(() => setCopied(false), 1500);
		} catch {
			setCopyError(true);
		}
	}, []);
	return (
		<div className="grid w-full max-w-xl gap-4 sm:grid-cols-2">
			<Field>
				<FieldLabel htmlFor="screen-link">Link de la pantalla</FieldLabel>
				<PrefixedInput
					id="screen-link"
					inputClassName="font-mono text-[13px]"
					prefix="/kiosk/"
					readOnly
					value="equipo-demo?token=ejemplo"
				/>
			</Field>
			<Field>
				<FieldLabel htmlFor="search">Buscar por idea</FieldLabel>
				<SearchInput
					id="search"
					placeholder="Buscá por idea, no solo por palabra"
				/>
			</Field>
			<Field>
				<FieldLabel htmlFor="send-code">Código</FieldLabel>
				<CopyField
					aria-label="send.moodinary.com/ABC123"
					copied={copied}
					copyLabel={copied ? "Link copiado" : "Copiar link"}
					id="send-code"
					onCopy={copy}
					prefix="send.moodinary.com/"
					value="ABC123"
				/>
				<FieldHint aria-live="polite">{copyHint(copyError, copied)}</FieldHint>
			</Field>
			<Field>
				<FieldLabel htmlFor="suffix-demo">Unidad (demostración)</FieldLabel>
				<SuffixInput
					defaultValue={50}
					id="suffix-demo"
					max={100}
					min={0}
					suffix="%"
					type="number"
				/>
			</Field>
		</div>
	);
}

Props

PrefixedInput

PropTipoDefaultDescripción
prefixReact.ReactNode-Texto fijo antes del valor editable.
inputClassNamestring-Clases del input; className se aplica al grupo.
...propsOmit<React.ComponentProps<"input">, "prefix">-Atributos nativos como id, value, disabled y onChange.

SearchInput

PropTipoDefaultDescripción
shortcutstring-Atajo visible. No registra un atajo de teclado por sí solo.
submitLabelstring-Agrega un botón submit para búsquedas dentro de un form.
...propsReact.ComponentProps<"input">-Atributos del campo de búsqueda.

CopyField

PropTipoDefaultDescripción
valuestring-Contenido de solo lectura.
onCopy() => void-Acción del botón. La escritura en el portapapeles queda a cargo del caller.
copiedboolean-Reemplaza el ícono de copiar por una confirmación.
copyLabelstring"Copiar"Nombre accesible del botón.
monobooleantrueUsa tipografía monoespaciada.
prefixstring-Prefijo apagado, fuera del valor copiable.

SuffixInput

PropTipoDefaultDescripción
suffixReact.ReactNode-Unidad fija a la derecha.
...propsReact.ComponentProps<"input">-Atributos nativos, por ejemplo type, min y step.

InputGroup / InputGroupAddon

PropTipoDefaultDescripción
align"start" | "end""start"En InputGroupAddon define el borde del prefijo o sufijo.
childrenReact.ReactNode-Composición con InputGroupInput, InputGroupIcon y InputGroupButton.

Cuándo sí y cuándo no

Hacé
  • Elegí la variante de propósito antes de componer a mano.
  • Mantené las unidades fuera del valor editable.
  • Confirmá la copia solo después de que el portapapeles responda.
Evitá
  • No incluyas secretos reales en los ejemplos.
  • No muestres un atajo que no funciona.
  • No uses un prefijo largo que deje sin espacio al valor en móvil.

Accesibilidad

  • Asociá el label al id del input, no al contenedor.
  • Tab recorre el campo y la acción; Enter envía si el botón es submit.
  • El botón de copiar necesita un nombre accesible concreto.