Saltar al contenido principal
NachUI

Actions

La fila de botones chicos con ícono debajo de un mensaje del asistente, con un botón de copiar que se confirma solo.

Keep the trigger and the region linked with aria-controls and aria-labelledby, and let the open state live in one place so both stay in sync.

1'use client';
2
3import { useState } from 'react';
4import { Actions } from '@/components/ui/actions';
5
6const ANSWER =
7 'Keep the trigger and the region linked with aria-controls and aria-labelledby, and let the open state live in one place so both stay in sync.';
8
9export function Default() {
10 const [vote, setVote] = useState<'up' | 'down' | null>(null);
11
12 return (
13 <div className="flex w-full max-w-md flex-col gap-2">
14 <p className="text-foreground/90 text-sm leading-relaxed">{ANSWER}</p>
15 <Actions>
16 <Actions.Copy text={ANSWER} />
17 <Actions.Button label="Retry">
18 <Actions.Icons.retry />
19 </Actions.Button>
20 <Actions.Button
21 label="Good response"
22 active={vote === 'up'}
23 onClick={() => setVote((current) => (current === 'up' ? null : 'up'))}
24 >
25 <Actions.Icons.thumbsUp />
26 </Actions.Button>
27 <Actions.Button
28 label="Bad response"
29 active={vote === 'down'}
30 onClick={() => setVote((current) => (current === 'down' ? null : 'down'))}
31 >
32 <Actions.Icons.thumbsDown />
33 </Actions.Button>
34 </Actions>
35 </div>
36 );
37}

Instalación

pnpm dlx nachui add actions

Anatomía

1import { Actions } from '@/components/ui/actions';
1<Actions>
2 <Actions.Copy text={answer} />
3 <Actions.Button label="Reintentar" onClick={regenerate}>
4 <Actions.Icons.retry />
5 </Actions.Button>
6 <Actions.Button label="Buena respuesta" active={vote === 'up'} onClick={voteUp}>
7 <Actions.Icons.thumbsUp />
8 </Actions.Button>
9</Actions>
Cada botón lleva un label. Es el nombre accesible y el tooltip nativo, así el ícono nunca queda como única descripción. active marca un estado presionado, por ejemplo el voto que el lector ya dio.

Composición

Usá la siguiente composición para construir Actions:
Actions
├── Actions.Copy
└── Actions.Button
└── Actions.Icons.*

Con un mensaje

Las acciones van naturales en un Message.Footer. Dejalas al principio de la fila en los mensajes del asistente y al final en los del lector.
Assistant
Done. I moved the open state up to the root and the region follows it.
1'use client';
2
3import { Actions } from '@/components/ui/actions';
4import { Bubble } from '@/components/ui/bubble';
5import { Message } from '@/components/ui/message';
6
7const ANSWER = 'Done. I moved the open state up to the root and the region follows it.';
8
9export function WithMessage() {
10 return (
11 <div className="w-full max-w-md">
12 <Message>
13 <Message.Content>
14 <Message.Header>Assistant</Message.Header>
15 <Bubble variant="secondary">
16 <Bubble.Content>{ANSWER}</Bubble.Content>
17 </Bubble>
18 <Message.Footer className="px-0">
19 <Actions>
20 <Actions.Copy text={ANSWER} />
21 <Actions.Button label="Retry">
22 <Actions.Icons.retry />
23 </Actions.Button>
24 <Actions.Button label="Share">
25 <Actions.Icons.share />
26 </Actions.Button>
27 </Actions>
28 </Message.Footer>
29 </Message.Content>
30 </Message>
31 </div>
32 );
33}

Copiar

Actions.Copy escribe text en el portapapeles y cambia a un tilde por un momento, con la etiqueta pasando a "Copied" para que los lectores de pantalla también reciban la confirmación. label, copiedLabel y timeout lo ajustan.

Íconos

Actions.Icons trae copy, check, retry, thumbsUp, thumbsDown y share como componentes SVG planos, así la fila típica no necesita ningún paquete de íconos. Cualquier SVG sirve como hijo.

Referencia de API

Actions

PropTypeDefaultDescription
align'start' | 'end''start'Lado de la fila donde van los botones
classNamestring-Clases CSS adicionales

Actions.Button

PropTypeDefaultDescription
labelstring-Nombre accesible y tooltip, obligatorio
activebooleanfalseEstado presionado, setea data-active
childrenReactNode-El ícono
classNamestring-Clases CSS adicionales

Actions.Copy

PropTypeDefaultDescription
textstring-Lo que se copia
labelstring'Copy'Etiqueta en reposo
copiedLabelstring'Copied'Etiqueta después de copiar
timeoutnumber1500Milisegundos hasta que vuelve la etiqueta
classNamestring-Clases CSS adicionales
¿Encontraste algo que mejorar?

¿Notaste un error, tipografía o detalle faltante en esta página? Ayúdanos a mejorar la documentación abriendo un issue en GitHub.

Crear un Issue