Syed Hasnain

Feedback Dialog

Component 1

About

Response feedback with copy, thumbs up and thumbs down actions that expands into a reason picker and an optional note.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Feedback Dialog to your project and fits it to your theme.

Code

How Feedback Dialog is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import * as React from 'react'
import { FeedbackDialog, type FeedbackRating } from '@/components/ui/feedback-dialog'

const note = 'The pricing numbers are from last year.'

const script: { comment: number; rating: FeedbackRating; reason?: string; wait: number }[] = [
  { rating: null, comment: 0, wait: 1000 },
  { rating: 'up', comment: 0, wait: 1600 },
  { rating: 'down', comment: 0, wait: 900 },
  { rating: 'down', reason: 'Outdated', comment: 0, wait: 700 },
]

export default function Demo() {
  const [step, setStep] = React.useState(3)
  const [typed, setTyped] = React.useState(note.length)
  const [auto, setAuto] = React.useState(true)
  const [rating, setRating] = React.useState<FeedbackRating>('down')
  const [reason, setReason] = React.useState<string | undefined>('Outdated')
  const [comment, setComment] = React.useState(note)

  React.useEffect(() => {
    if (!auto) return
    const typing = step === script.length - 1 && typed < note.length
    const timer = setTimeout(
      () => {
        if (typing) {
          setTyped((value) => value + 1)
          setComment(note.slice(0, typed + 1))
          return
        }
        const next = (step + 1) % (script.length + 1)
        if (next === script.length) return setStep(next)
        const frame = script[next]
        setStep(next)
        setRating(frame.rating)
        setReason(frame.reason)
        setTyped(0)
        setComment('')
      },
      typing ? 40 : step === script.length ? 3200 : script[step].wait,
    )
    return () => clearTimeout(timer)
  }, [auto, step, typed])

  return (
    <div className="w-full max-w-lg" onPointerDown={() => setAuto(false)}>
      <p className="mb-2 text-sm leading-6 font-[450] tracking-[-0.05px] text-muted-foreground">
        The Pro plan costs $18 per seat each month and includes unlimited projects, priority
        support, and audit logs.
      </p>
      <FeedbackDialog
        comment={comment}
        onCommentChange={setComment}
        onRatingChange={setRating}
        onReasonChange={setReason}
        rating={rating}
        reason={reason}
        reasons={['Incorrect', 'Outdated', 'Too vague', 'Missing sources']}
      />
    </div>
  )
}

Dependencies

More by Syed Hasnain

View all
  • Color Picker

    Color Picker

    77
  • Cost Meter

    Cost Meter

    29
  • Quota Banner

    Quota Banner

    21
  • Message Scroller

    Message Scroller

    21
  • Commit

    Commit

    17
  • Image Generation Loader

    Image Generation Loader

    15
  • Attachments

    Attachments

    15
  • Citations

    Citations

    14

Explore more

Part of Pasta UI — browse the full library on 21st.dev.