Saltar al contenido
ssntl/ui

Input

Un campo de texto de 48px: foco visible, un borde 3:1 sobre cualquier superficie y errores con aria-invalid.

Instalación

$ pnpm dlx shadcn@latest add @ssntl/input

Uso

tsx
import { Input } from "@/components/ui/input"

<Input type="email" autoComplete="email" placeholder="ana@studio.com" />
  • Mide 48px, igual que los botones, para que un campo y su acción se alineen.
  • El borde usa el token input (3:1 sobre cualquier superficie); el foco lo oscurece y muestra el anillo.
  • Usa el type y autoComplete correctos. El placeholder muestra un valor de ejemplo, nunca la etiqueta.
  • Los errores salen de aria-invalid y una pista que dice cómo corregirlo (ver Field).

Código

components/ui/input.tsx
import * as React from "react"

import { cn } from "@/lib/utils"

// Essential Design `es-input`: 48px (the height of buttons), `card` fill, a 1px
// `input` border that meets 3:1 on every surface, `radius-sm`. Focus darkens the
// border and shows the ring; errors come from aria-invalid, never color alone.
function Input({
  className,
  type = "text",
  ...props
}: React.ComponentProps<"input">) {
  return (
    <input
      data-slot="input"
      type={type}
      className={cn(
        "h-12 w-full min-w-0 rounded-sm border border-input bg-card px-4 text-body text-foreground",
        "transition-[border-color] duration-(--duration-fast) ease-out placeholder:text-muted-foreground",
        "hover:border-muted-foreground focus:border-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
        "disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-destructive",
        "file:mr-3 file:border-0 file:bg-transparent file:font-medium",
        className
      )}
      {...props}
    />
  )
}

export { Input }