Components / AI Chat Interfaces
AI Response Actions
An action bar for AI responses with copy, regenerate, thumbs up/down, and share buttons with tooltip labels.
Components / AI Chat Interfaces
An action bar for AI responses with copy, regenerate, thumbs up/down, and share buttons with tooltip labels.
Install the core libraries required for this component.
npm install react lucide-reactAdd the necessary Shadcn UI primitives.
npx shadcn-ui@latest add card avatar button tooltipimport { useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
import { Copy, RefreshCcw, ThumbsUp, ThumbsDown, Share2 } from "lucide-react";
interface AIResponseWithActionsProps {
author?: string;
avatar?: string;
text?: string;
}
export default function AIResponseWithActions({
author = "ChatGPT",
avatar = "https://i.pravatar.cc/40?img=12",
text = "This is a sample AI response with interactive actions.",
}: AIResponseWithActionsProps) {
const [copied, setCopied] = useState(false);
const [liked, setLiked] = useState(false);
const [disliked, setDisliked] = useState(false);
const handleCopy = () => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
const handleLike = () => {
setLiked((prev) => !prev);
if (disliked) setDisliked(false);
};
const handleDislike = () => {
setDisliked((prev) => !prev);
if (liked) setLiked(false);
};
const handleRegenerate = () => {
console.log("Regenerate response clicked");
};
const handleShare = () => {
console.log("Share response clicked");
};
return (
<Card className="border-0 w-full">
<CardContent className="flex flex-col gap-2 p-3">
{/* Message Bubble */}
<div className="flex items-start gap-3">
<Avatar>
<AvatarImage src={avatar} />
<AvatarFallback>{author[0]}</AvatarFallback>
</Avatar>
<div className="bg-gray-100 text-gray-900 p-3 rounded-lg flex-1">
{text}
</div>
</div>
{/* Action Bar */}
<div className="flex items-center gap-2 mt-1">
{/* Copy */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleCopy}>
<Copy className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{copied ? "Copied!" : "Copy"}</TooltipContent>
</Tooltip>
{/* Regenerate */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleRegenerate}>
<RefreshCcw className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Regenerate</TooltipContent>
</Tooltip>
{/* Thumbs Up */}
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
variant={liked ? "default" : "outline"}
onClick={handleLike}
>
<ThumbsUp className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{liked ? "Liked" : "Like"}</TooltipContent>
</Tooltip>
{/* Thumbs Down */}
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
variant={disliked ? "destructive" : "outline"}
onClick={handleDislike}
>
<ThumbsDown className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{disliked ? "Disliked" : "Dislike"}</TooltipContent>
</Tooltip>
{/* Share */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleShare}>
<Share2 className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Share</TooltipContent>
</Tooltip>
</div>
</CardContent>
</Card>
);
} import { useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
import { Copy, RefreshCcw, ThumbsUp, ThumbsDown, Share2 } from "lucide-react";
interface AIResponseWithActionsProps {
author?: string;
avatar?: string;
text?: string;
}
export default function AIResponseWithActions({
author = "ChatGPT",
avatar = "https://i.pravatar.cc/40?img=12",
text = "This is a sample AI response with interactive actions.",
}: AIResponseWithActionsProps) {
const [copied, setCopied] = useState(false);
const [liked, setLiked] = useState(false);
const [disliked, setDisliked] = useState(false);
const handleCopy = () => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
const handleLike = () => {
setLiked((prev) => !prev);
if (disliked) setDisliked(false);
};
const handleDislike = () => {
setDisliked((prev) => !prev);
if (liked) setLiked(false);
};
const handleRegenerate = () => {
console.log("Regenerate response clicked");
};
const handleShare = () => {
console.log("Share response clicked");
};
return (
<Card className="border-0 w-full">
<CardContent className="flex flex-col gap-2 p-3">
{/* Message Bubble */}
<div className="flex items-start gap-3">
<Avatar>
<AvatarImage src={avatar} />
<AvatarFallback>{author[0]}</AvatarFallback>
</Avatar>
<div className="bg-gray-100 text-gray-900 p-3 rounded-lg flex-1">
{text}
</div>
</div>
{/* Action Bar */}
<div className="flex items-center gap-2 mt-1">
{/* Copy */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleCopy}>
<Copy className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{copied ? "Copied!" : "Copy"}</TooltipContent>
</Tooltip>
{/* Regenerate */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleRegenerate}>
<RefreshCcw className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Regenerate</TooltipContent>
</Tooltip>
{/* Thumbs Up */}
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
variant={liked ? "default" : "outline"}
onClick={handleLike}
>
<ThumbsUp className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{liked ? "Liked" : "Like"}</TooltipContent>
</Tooltip>
{/* Thumbs Down */}
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
variant={disliked ? "destructive" : "outline"}
onClick={handleDislike}
>
<ThumbsDown className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{disliked ? "Disliked" : "Dislike"}</TooltipContent>
</Tooltip>
{/* Share */}
<Tooltip>
<TooltipTrigger asChild>
<Button size="sm" variant="outline" onClick={handleShare}>
<Share2 className="w-4 h-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Share</TooltipContent>
</Tooltip>
</div>
</CardContent>
</Card>
);
}
Primitives required in your
@/components/ui
directory.
| Component | Path |
|---|---|
| card | @/components/ui/card |
| avatar | @/components/ui/avatar |
| button | @/components/ui/button |
| tooltip | @/components/ui/tooltip |
Types and interfaces defined in this component.
interface AIResponseWithActionsProps {
author?: string;
avatar?: string;
text?: string;
} interface AIResponseWithActionsProps {
author?: string;
avatar?: string;
text?: string;
} Internal functions used to handle component logic.
| Function | Parameters |
|---|---|
| handleCopy() | None |
| handleLike() | None |
| handleDislike() | None |
| handleRegenerate() | None |
| handleShare() | None |
| AIResponseWithActions() | { author = "ChatGPT", avatar = "https://i.pravatar.cc/40?img=12", text = "This is a sample AI response with interactive actions.", }: AIResponseWithActionsProps |
React state variables managed within this component.
| Variable | Initial Value |
|---|---|
| copied | false |
| liked | false |
| disliked | false |
Every JSX/HTML tag used in this component, with usage count and source.
| Tag | Count | Type | Source |
|---|---|---|---|
| <Avatar> | 1× | | @/components/ui/avatar |
| <AvatarFallback> | 1× | | @/components/ui/avatar |
| <AvatarImage> | 1× | | @/components/ui/avatar |
| <Card> | 1× | | @/components/ui/card |
| <CardContent> | 1× | | @/components/ui/card |
| <Copy> | 1× | | lucide-react |
| <RefreshCcw> | 1× | | lucide-react |
| <Share2> | 1× | | lucide-react |
| <ThumbsDown> | 1× | | lucide-react |
| <ThumbsUp> | 1× | | lucide-react |
| <Tooltip> | 5× | | @/components/ui/tooltip |
| <TooltipContent> | 5× | | @/components/ui/tooltip |
| <TooltipTrigger> | 5× | | @/components/ui/tooltip |
| <Button> | 5× | | Native HTML |
| <div> | 3× | | Native HTML |