User feedback

Collect topic, rating, and comment feedback from the same visitor and contact context as your support widget.

User feedback is more useful when it is not anonymous.

Cossistant feedback uses the same visitor context as SupportProvider. When a visitor leaves a rating, topic, or comment, the submission can be attached to the visitor, and to the contact when that visitor is identified. That means your team can understand who was blocked, see the context around the feedback, and follow up in a conversation instead of reading a detached survey response.

Use the default <Feedback /> widget when you want the fastest path. Use useFeedbackForm when you want the same feedback engine inside your own shadcn UI.

Before you start

Complete the React quickstart first. Your app should already have:

  • @cossistant/react installed
  • SupportProvider configured with your public key
  • one Cossistant CSS entrypoint imported at your app root
tssrc/main.tsx
import { SupportProvider } from "@cossistant/react";
import type { ReactNode } from "react";
import "@cossistant/react/styles.css";
 
export function AppRoot({ children }: { children: ReactNode }) {
  return <SupportProvider publicKey="pk_test_xxxx">{children}</SupportProvider>;
}

SupportProvider is what gives feedback its power. The hooks use it to access the Cossistant client, website, visitor, and contact context.

Fastest path

Render the default widget when you want a complete feedback popover without owning the UI.

tssrc/App.tsx
import { Feedback } from "@cossistant/react";
 
export function App() {
  return (
    <Feedback
      topics={["Bug", "Feature request", "UX", "Other"]}
      trigger="product_feedback"
    />
  );
}

The trigger value is your label for why this feedback was collected. Use names like product_feedback, churn, nps_survey, or conversation_resolved.

Install the shadcn examples

The examples below use Cossistant for feedback state and shadcn components for the interface.

If Cossistant is not installed yet:

pnpm add @cossistant/react

Install the shadcn components used by the examples:

pnpm dlx shadcn@latest add button popover select textarea toggle-group

Then open the Code tab on either preview and copy the component into your app. Both examples import useFeedbackForm from @cossistant/react/feedback, so they submit through the same visitor and contact context as your support widget.

Emoji feedback

Start with a compact popover: topic, comment, rating, and a small send button.

Star feedback

The same hook can power a five-star rating UI.

Build your own

Use useFeedbackForm when you want full control over the UI but do not want to rebuild form state, validation, or submission plumbing.

tscomponents/product-feedback.tsx
"use client";
 
import { useFeedbackForm } from "@cossistant/react/feedback";
 
export function ProductFeedback() {
  const feedback = useFeedbackForm({
    topics: ["Bug", "Feature request", "UX", "Other"],
    trigger: "product_feedback",
    commentRequired: true,
  });
 
  return (
    <form onSubmit={feedback.handleSubmit}>
      <select
        aria-invalid={feedback.fields.topic.isMissing}
        onBlur={feedback.fields.topic.handleBlur}
        onChange={(event) => feedback.handleTopicChange(event.target.value)}
        value={feedback.topic}
      >
        <option value="">Select topic</option>
        {feedback.availableTopics.map((topic) => (
          <option key={topic} value={topic}>
            {topic}
          </option>
        ))}
      </select>
 
      <textarea
        aria-invalid={feedback.fields.comment.isMissing}
        onBlur={feedback.fields.comment.handleBlur}
        onChange={(event) => feedback.handleCommentChange(event.target.value)}
        value={feedback.comment}
      />
 
      {[1, 2, 3, 4, 5].map((rating) => (
        <button
          key={rating}
          onClick={() => feedback.handleRatingSelect(rating)}
          type="button"
        >
          {rating}
        </button>
      ))}
 
      <button disabled={feedback.submit.disabled} type="submit">
        {feedback.submit.label}
      </button>
    </form>
  );
}

useFeedbackForm manages the moving pieces that every feedback UI needs:

  • open state with open, setOpen, and handleOpenChange
  • rating state with rating, hoveredRating, handleRatingSelect, and handleRatingHoverChange
  • topic and comment state with normalized values
  • validation state for required rating, topics, and comments
  • pending, error, and submitted states
  • success actions with sendAnother and done

The most common options are:

  • topics: the selectable feedback categories
  • defaultTopic: a preselected topic from topics
  • trigger: the reason this feedback form appeared
  • conversationId: attach the feedback to a specific support conversation
  • commentRequired: require a written comment before submit
  • defaultOpen: start the popover or dialog open
  • onSuccess: run code after Cossistant stores the feedback
  • onError: handle a failed submission

Lower-level submit API

Use useSubmitFeedback when you already own the entire form and only need the mutation.

tscomponents/custom-feedback-submit.tsx
"use client";
 
import { useSubmitFeedback } from "@cossistant/react/feedback";
 
export function CustomFeedbackSubmit() {
  const feedback = useSubmitFeedback();
 
  async function submit() {
    await feedback.mutateAsync({
      rating: 5,
      topic: "UX",
      comment: "The new onboarding screen is much clearer.",
      trigger: "onboarding_feedback",
    });
  }
 
  return (
    <button disabled={feedback.isPending} onClick={submit} type="button">
      Send feedback
    </button>
  );
}

useSubmitFeedback reads the Cossistant client, visitor, website, and contact context from SupportProvider. In most apps, pass rating, topic, comment, trigger, and optionally conversationId. The hook fills visitorId and contactId from context.

Only pass visitorId or contactId manually if you are building a lower-level integration and you know you need to override the context.

Feedback data

Every submission stores:

  • rating: required, from 1 to 5
  • topic: optional structured category
  • comment: optional written feedback
  • trigger: optional label for what prompted the form
  • source: defaults to widget
  • conversationId: optional conversation link
  • visitorId: the visitor who left the feedback
  • contactId: the identified contact, when the visitor has one

That association is the important part. A low rating from a signed-in customer can become a real support follow-up, not just a number in a dashboard.

Hook exports

useFeedbackForm and useSubmitFeedback are exported from @cossistant/react/hooks and @cossistant/react/feedback. Next.js apps can use the matching @cossistant/next/hooks and @cossistant/next/feedback exports.

Type reference

Feedback props

Prop

Type

useFeedbackForm options

Prop

Type

useFeedbackForm result

Name

Type

Submit feedback variables

Parameter

Type