Was this response helpful?
import * as React from "react";
import {
HandThumbDownIcon,
HandThumbUpIcon,
XMarkIcon,
} from "@heroicons-animated/react";
import { Button } from "@/components/ui/button";
import {
FeedbackBar,
FeedbackBarAction,
FeedbackBarActions,
FeedbackBarClose,
FeedbackBarContent,
FeedbackBarLabel,
FeedbackBarPrompt,
} from "@/components/pandacoderz-ui/feedback-bar";
export default function FeedbackBarDemo() {
const [state, setState] = React.useState<"idle" | "done" | "closed">("idle");
if (state === "closed") {
return (
<Button variant="outline" size="sm" onClick={() => setState("idle")}>
Show feedback bar
</Button>
);
}
return (
<FeedbackBar>
<FeedbackBarContent>
<FeedbackBarPrompt>
<FeedbackBarLabel>
{state === "done" ? "Thanks for the feedback!" : "Was this response helpful?"}
</FeedbackBarLabel>
</FeedbackBarPrompt>
{state === "idle" ? (
<FeedbackBarActions>
<FeedbackBarAction asChild tooltip={{ content: "Good", shortcut: "G" }}>
<Button variant="ghost" size="icon-sm" className="rounded-full text-muted-foreground" aria-label="Good" onClick={() => setState("done")}>
<HandThumbUpIcon size={16} className="flex" />
</Button>
</FeedbackBarAction>
<FeedbackBarAction asChild tooltip={{ content: "Bad", shortcut: "B" }}>
<Button variant="ghost" size="icon-sm" className="rounded-full text-muted-foreground" aria-label="Bad" onClick={() => setState("done")}>
<HandThumbDownIcon size={16} className="flex" />
</Button>
</FeedbackBarAction>
</FeedbackBarActions>
) : null}
<FeedbackBarClose tooltip="Dismiss">
<Button variant="ghost" size="icon-sm" className="rounded-full text-muted-foreground" aria-label="Dismiss" onClick={() => setState("closed")}>
<XMarkIcon size={16} className="flex" />
</Button>
</FeedbackBarClose>
</FeedbackBarContent>
</FeedbackBar>
);
}Installation
npx shadcn@latest add https://ui.spencerwueste.com/r/feedback-bar.jsonpnpm dlx shadcn@latest add https://ui.spencerwueste.com/r/feedback-bar.jsonyarn dlx shadcn@latest add https://ui.spencerwueste.com/r/feedback-bar.jsonbunx --bun shadcn@latest add https://ui.spencerwueste.com/r/feedback-bar.jsonInstall the dependencies:
npm install radix-uiAdd the shadcn primitives it builds on:
npx shadcn@latest add tooltip kbdCopy the source into your project:
import * as React from "react";
import { Slot } from "radix-ui";
import { cn } from "@/lib/utils";
import { Kbd } from "@/components/ui/kbd";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
type FeedbackBarTooltip =
| string
| {
content?: string;
side?: "top" | "right" | "bottom" | "left";
shortcut?: string;
};
type FeedbackBarProps = React.HTMLAttributes<HTMLDivElement>;
function FeedbackBar({ className, ...props }: FeedbackBarProps) {
return (
<div
data-slot="feedback-bar"
role="group"
aria-label="Feedback bar"
className={cn(
"inline-flex h-12 w-full max-w-110 rounded-xl border bg-card text-sm shadow-xs dark:border-accent",
className,
)}
{...props}
/>
);
}
type FeedbackBarContentProps = React.HTMLAttributes<HTMLDivElement>;
function FeedbackBarContent({ className, ...props }: FeedbackBarContentProps) {
return (
<div
data-slot="feedback-bar-content"
className={cn("flex w-full items-center justify-between", className)}
{...props}
/>
);
}
type FeedbackBarPromptProps = React.HTMLAttributes<HTMLDivElement>;
function FeedbackBarPrompt({ className, ...props }: FeedbackBarPromptProps) {
return (
<div
data-slot="feedback-bar-prompt"
className={cn(
"flex h-full w-full items-center justify-start gap-2.5 pl-4",
className,
)}
{...props}
/>
);
}
type FeedbackBarLabelProps = React.HTMLAttributes<HTMLSpanElement>;
function FeedbackBarLabel({ className, ...props }: FeedbackBarLabelProps) {
return (
<span
data-slot="feedback-bar-label"
className={cn("text-sm font-[350] text-foreground", className)}
{...props}
/>
);
}
type FeedbackBarActionsProps = React.HTMLAttributes<HTMLDivElement>;
function FeedbackBarActions({ className, ...props }: FeedbackBarActionsProps) {
return (
<div
data-slot="feedback-bar-actions"
className={cn(
"flex h-full items-center justify-center gap-1.5 px-2",
className,
)}
{...props}
/>
);
}
type FeedbackBarActionProps = React.HTMLAttributes<HTMLDivElement> & {
asChild?: boolean;
tooltip?: FeedbackBarTooltip;
};
function FeedbackBarAction({
asChild = false,
tooltip,
className,
...props
}: FeedbackBarActionProps) {
const Comp = asChild ? Slot.Root : "div";
const { content, side, shortcut } =
typeof tooltip === "string" ? { content: tooltip } : (tooltip ?? {});
if (!content) {
return (
<Comp
data-slot="feedback-bar-action"
className={cn(className)}
{...props}
/>
);
}
return (
<TooltipProvider delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<Comp
data-slot="feedback-bar-action"
className={cn(className)}
{...props}
/>
</TooltipTrigger>
<TooltipContent className="rounded-full" side={side}>
{content}
{shortcut ? <Kbd className="rounded-md!">{shortcut}</Kbd> : null}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
type FeedbackBarCloseProps = React.HTMLAttributes<HTMLDivElement> & {
tooltip?: FeedbackBarTooltip;
};
function FeedbackBarClose({
className,
children,
...props
}: FeedbackBarCloseProps) {
return (
<FeedbackBarAction
asChild
className={cn(
"flex h-full items-center justify-center border-l px-2 dark:border-accent",
className,
)}
{...props}
>
<div data-slot="feedback-bar-close">{children}</div>
</FeedbackBarAction>
);
}
export {
FeedbackBar,
FeedbackBarContent,
FeedbackBarPrompt,
FeedbackBarLabel,
FeedbackBarActions,
FeedbackBarAction,
FeedbackBarClose,
};Usage
import {
FeedbackBar,
FeedbackBarAction,
FeedbackBarActions,
FeedbackBarClose,
FeedbackBarContent,
FeedbackBarLabel,
FeedbackBarPrompt,
} from "@/components/pandacoderz-ui/feedback-bar";<FeedbackBar>
<FeedbackBarContent>
<FeedbackBarPrompt>
<FeedbackBarLabel>Was this response helpful?</FeedbackBarLabel>
</FeedbackBarPrompt>
<FeedbackBarActions>
<FeedbackBarAction asChild tooltip="Good">
<Button variant="ghost" size="icon-sm">…</Button>
</FeedbackBarAction>
</FeedbackBarActions>
<FeedbackBarClose tooltip="Dismiss">
<Button variant="ghost" size="icon-sm">…</Button>
</FeedbackBarClose>
</FeedbackBarContent>
</FeedbackBar>API Reference
FeedbackBarAction
| Prop | Type | Description |
|---|---|---|
asChild |
boolean |
Merge into the child element. |
tooltip |
string | { content, side, shortcut } |
Tooltip content and optional keyboard hint. |
FeedbackBarClose
Same props as FeedbackBarAction, rendered with a left border and always asChild.