Attachment
Tarjetas de archivos e imágenes para subidas, con progreso, estados, acciones, un trigger de tarjeta completa y nombres que conservan su extensión.
pnpm dlx shadcn@latest add https://hextaui.com/r/attachment.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/attachment.tsx components/ui/aspect-ratio.tsx components/ui/skeleton.tsx components/ui/button.tsx components/ui/progress.tsx components/ui/scroll-area.tsx lib/motion.ts Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Imagen
variant="image" en <AttachmentMedia /> muestra una miniatura cuadrada con shimmer mientras carga. Define orientation="vertical" para un mosaico con la vista previa arriba.
Estados
state cubre todo el ciclo de vida de la subida. Los archivos en reposo (idle) tienen un borde discontinuo, los títulos en subida (uploading) y procesamiento (processing) tienen shimmer, y los errores tiñen de rojo el elemento multimedia y la descripción.
Flujo de subida
Pasa progress mientras state="uploading" para dibujar una barra de progreso fina a lo largo del borde inferior. Las vistas previas de imagen permanecen atenuadas hasta que termina la subida.
Tamaños
size escala el relleno, el elemento multimedia y el texto a la vez, y mantiene las esquinas interiores concéntricas con la tarjeta.
Nombres largos
Los nombres de archivo largos se truncan antes de la extensión, para que se siga distinguiendo un .pdf de un .zip. Pasa el cursor sobre el nombre para leerlo completo.
Group
<AttachmentGroup /> coloca los archivos adjuntos en una fila con desplazamiento lateral, con bordes que se desvanecen y elementos que se ajustan a su posición.
Trigger
<AttachmentTrigger /> hace clicable toda la tarjeta, por ejemplo para abrir una vista previa o un enlace, mientras las acciones que contiene siguen siendo independientes. Dale un aria-label.
Compositor
Los archivos añadidos después de cargar la página aparecen con un efecto pop, y el resto de la fila se desliza suavemente cuando se quita uno.
Imagen rota
Cuando falla la carga de la vista previa de una imagen, se recurre a un icono de archivo.
Estrés
Nombres hostiles en una columna estrecha, un estado aleatorio cada 60 ms y 200 elementos en un grupo. Nada se desborda y el diseño aguanta.
De derecha a izquierda
El elemento multimedia, el contenido y las acciones se reflejan, y la barra de progreso se llena desde el borde inicial.
| Key | Acción |
|---|---|
| Tab | Mueve el foco a cada acción y luego al trigger. Las acciones ocultas en mosaicos verticales aparecen cuando el foco entra en la tarjeta. |
| EnterSpace | Activa la acción o el trigger con foco. |
- Durante la subida, la barra de progreso tiene
role="progressbar"y se etiqueta con el título. - Los títulos de tipo cadena reciben un atributo
titlecon el nombre completo, de modo que los nombres truncados se puedan leer igualmente. - Las acciones solo con icono y el trigger no tienen texto, así que dales siempre un
aria-labelque nombre el archivo. - Con movimiento reducido, los adjuntos aparecen sin efecto pop, la barra de progreso salta en lugar de suavizarse y los grupos se reacomodan al instante.
Todas las partes excepto el grupo, la acción y el trigger renderizan un elemento simple y aceptan sus atributos. Los estilos de la tarjeta se exportan como attachmentVariants.
| Prop | Tipo | Predeterminado |
|---|---|---|
state | "idle" | "uploading" | "processing" | "error" | "done" | "done" |
progressDe 0 a 100. Se muestra solo durante la subida, y se limita a ese rango. | number | – |
size | "default" | "sm" | "xs" | "default" |
orientation | "horizontal" | "vertical" | "horizontal" |
| Atributo | Descripción |
|---|---|
data-slot="attachment" | Apunta a la tarjeta en CSS. |
data-state | El estado actual. |
data-size | El tamaño actual. |
data-orientation | La orientación actual. |
data-slot="attachment-progress" | La barra de progreso, presente durante la subida. |
--attachment-radius | El radio de las esquinas de la tarjeta. Las esquinas interiores se derivan de él. |
| Prop | Tipo | Predeterminado |
|---|---|---|
variantimage envuelve a su hijo en un AspectRatio cuadrado con un icono de archivo como fallback. | "icon" | "image" | "icon" |
| Atributo | Descripción |
|---|---|
data-slot="attachment-media" | Selecciona el elemento multimedia en CSS. |
data-variant | La variante actual. |
Un <div> que contiene el título y la descripción y ocupa el ancho restante.
| Atributo | Descripción |
|---|---|
data-slot="attachment-content" | Selecciona el contenido en CSS. |
| Prop | Tipo | Predeterminado |
|---|---|---|
childrenUna cadena se divide para que su extensión nunca se trunque. | ReactNode | – |
titleSe muestra al pasar el cursor. Por defecto es el nombre completo. | string | children |
idSe genera si se omite. La barra de progreso se etiqueta con él. | string | – |
| Atributo | Descripción |
|---|---|
data-slot="attachment-title" | Apunta al título en CSS. |
Un <span> de una sola línea para el tamaño, el tipo o el estado. Se trunca cuando se acaba el espacio.
| Atributo | Descripción |
|---|---|
data-slot="attachment-description" | Apunta a la descripción en CSS. |
Un <div> para los botones de acción. En mosaicos verticales flota sobre la vista previa y, en dispositivos con ratón, aparece al pasar el cursor o al recibir foco.
| Atributo | Descripción |
|---|---|
data-slot="attachment-actions" | Selecciona las acciones en CSS. |
Un <Button /> que se sitúa sobre el trigger. Acepta todas las props de Button.
| Prop | Tipo | Predeterminado |
|---|---|---|
variant | ButtonVariant | "ghost" |
size | ButtonSize | "icon-xs" |
| Atributo | Descripción |
|---|---|
data-slot="attachment-action" | Selecciona las acciones en CSS. |
Una capa invisible que cubre toda la tarjeta. Compónla con un trigger de diálogo, un enlace o cualquier botón.
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <button type="button"> |
| Atributo | Descripción |
|---|---|
data-slot="attachment-trigger" | Apunta al trigger en CSS. |
Un <ScrollArea /> horizontal que se ajusta a cada adjunto y anima la fila cuando se añaden o quitan elementos. Acepta todas las props de ScrollArea excepto scrollbars.
| Atributo | Descripción |
|---|---|
data-slot="attachment-group" | Apunta al grupo en CSS. |
data-slot="attachment-group-list" | La fila que contiene los adjuntos. |
- Aspect ratioUn contenedor que mantiene su forma antes de que cargue el contenido multimedia, muestra un brillo mientras carga, hace aparecer el contenido con un fundido y muestra una alternativa si falla.
- ButtonBotones en todas las variantes y tamaños, con un flujo integrado de carga, éxito y error que omite el spinner en las peticiones rápidas.
- MotionLas curvas de easing, duraciones y la comprobación de movimiento reducido con las que se anima cada componente, además de hooks para transformaciones de tamaño y resaltados deslizantes.
- ProgressUna barra o anillo que muestra cuánto ha avanzado una tarea, se suaviza entre actualizaciones y se desliza mientras el total es desconocido.
- Scroll areaScroll nativo con una barra de desplazamiento mínima, bordes que se desvanecen solo donde hay más por ver y un vistazo opcional que corta el último elemento por la mitad.
- BubbleBurbujas de mensajes de chat con variantes, esquinas agrupadas, reacciones y espacio para contenido interactivo.
Usado en bloques
Bloques que se construyen sobre Attachment.
- Prompt InputUn compositor de chat que empieza como una línea tranquila, crece hasta convertirse en una tarjeta mientras escribes y baja cuando empieza la conversación. Enter envía, de forma segura con entrada en japonés y chino. Pega, suelta o elige archivos con vistas previas, progreso y reintento. @ añade archivos y / ejecuta comandos desde un menú junto al cursor. Un selector de modelo con teclas numéricas, un control deslizante de esfuerzo que cobra vida en Max, un anillo de contexto, dictado con forma de onda en vivo, chips de herramientas, una cola para los mensajes escritos mientras se transmite una respuesta y borradores que sobreviven a una recarga.
- Chat ThreadToda la conversación alrededor del compositor. Tu pregunta se fija arriba mientras la respuesta llega en streaming, los puntos de control del lateral saltan entre mensajes, y cada respuesta se puede copiar, editar, reintentar, valorar y cambiar entre versiones. Las respuestas renderizan Markdown con bloques de código, tablas y citas, y el razonamiento, las llamadas a herramientas y Prompt Input encajan directamente.