feat(docs): DR-7574 Add page feedback widget#7613
Conversation
WalkthroughAdds a new client-side PageFeedback component to the docs app that captures per-page upvotes/downvotes (with optional comment), persists state to localStorage keyed by pathname, and emits PostHog analytics; integrates the component into the DocsPage layout after the header. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Page as DocsPage / PageFeedback
participant Storage as localStorage
participant PH as PostHog
User->>Page: View page (usePathname)
Page->>Storage: read(getStorageKey(path))
Storage-->>Page: stored state (idle/downvoted/submitted)
User->>Page: Click Upvote
Page->>Storage: write(vote=up)
Page->>PH: send event {path, vote:"up", comment:null}
PH-->>Page: ack (async)
Page-->>User: show "Thanks for your feedback!"
User->>Page: Click Downvote
Page-->>User: show comment textarea
User->>Page: Submit comment
Page->>Storage: write(vote=down, comment)
Page->>PH: send event {path, vote:"down", comment}
PH-->>Page: ack (async)
Page-->>User: show "Thanks for your feedback!"
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
apps/docs/src/components/page-feedback.tsx (2)
21-26: Consider logging localStorage errors rather than swallowing them silently.Empty catch blocks make debugging difficult when things go wrong in production. While localStorage failures are typically non-critical, having visibility into them helps diagnose user-reported issues.
🔧 Proposed improvement
useEffect(() => { try { const stored = localStorage.getItem(getStorageKey(pathname)); if (stored) setState("submitted"); - } catch {} + } catch (e) { + console.warn("[PageFeedback] localStorage read failed:", e); + } }, [pathname]);Apply similarly to the
persistfunction's localStorage write.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/components/page-feedback.tsx` around lines 21 - 26, The catch block in the useEffect that reads from localStorage (around getStorageKey(pathname) and setState("submitted")) silently swallows errors; update it to catch the error as e and log a helpful message (including e) via the app logger or console.error so failures are visible; also apply the same pattern to the persist function where localStorage writes occur so both read and write paths surface errors rather than using empty catch blocks.
97-103: Add accessibility attributes to the textarea.The textarea lacks an
idand associated<label>, which makes it harder for screen reader users to understand its purpose. Theplaceholderalone isn't sufficient for accessibility.♿ Proposed accessibility improvement
+ <label htmlFor="feedback-comment" className="sr-only"> + What was missing or unclear? + </label> <textarea + id="feedback-comment" value={comment} onChange={(e) => setComment(e.target.value)} placeholder="What was missing or unclear? (optional)" + aria-label="Feedback comment" rows={3}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/components/page-feedback.tsx` around lines 97 - 103, The textarea in the PageFeedback component is missing an id and an associated label which hurts screen-reader accessibility; add a unique id (e.g., feedbackCommentId) and provide a corresponding <label htmlFor={feedbackCommentId}> that describes the field (or use a visually-hidden label if you don't want visible text), or alternatively add an explicit aria-label/aria-labelledby tied to that id, and update the textarea to include id={feedbackCommentId} so the label and textarea are programmatically associated (reference the textarea using the existing state handlers comment and setComment to locate the element).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs/src/components/page-feedback.tsx`:
- Around line 15-26: The component can flash "idle" before the client-side
localStorage check runs; change the initial feedback state in PageFeedback from
"idle" to a sentinel like "loading" (or null), update the useEffect that reads
localStorage/getStorageKey(pathname) to setState to either "submitted" or "idle"
when the check completes, and ensure the render logic returns nothing (or a
skeleton) while state === "loading" so users who already submitted won't see the
prompt during hydration; keep references to usePathname, state/setState,
useEffect and getStorageKey to locate the changes.
- Line 7: The PostHog SDK is never initialized before posthog.capture() is
called; import or run the posthog.init() initialization so captures aren't
dropped. Fix by ensuring instrumentation-client.ts (which calls posthog.init())
is imported and executed on the client before app render (e.g., import it from
the root layout or Provider), or move the posthog.init() call into the existing
instrumentation.ts initialization flow, or create a client-side PostHog provider
that runs posthog.init() during its mount before rendering children; refer to
instrumentation-client.ts, instrumentation.ts, posthog.init, and posthog.capture
when applying the change.
---
Nitpick comments:
In `@apps/docs/src/components/page-feedback.tsx`:
- Around line 21-26: The catch block in the useEffect that reads from
localStorage (around getStorageKey(pathname) and setState("submitted")) silently
swallows errors; update it to catch the error as e and log a helpful message
(including e) via the app logger or console.error so failures are visible; also
apply the same pattern to the persist function where localStorage writes occur
so both read and write paths surface errors rather than using empty catch
blocks.
- Around line 97-103: The textarea in the PageFeedback component is missing an
id and an associated label which hurts screen-reader accessibility; add a unique
id (e.g., feedbackCommentId) and provide a corresponding <label
htmlFor={feedbackCommentId}> that describes the field (or use a visually-hidden
label if you don't want visible text), or alternatively add an explicit
aria-label/aria-labelledby tied to that id, and update the textarea to include
id={feedbackCommentId} so the label and textarea are programmatically associated
(reference the textarea using the existing state handlers comment and setComment
to locate the element).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6bb6c769-5310-4b05-a75d-5f7c178d5bd5
📒 Files selected for processing (2)
apps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsxapps/docs/src/components/page-feedback.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/docs/src/components/page-feedback.tsx (1)
101-107: Consider adding an accessible label for the textarea.The textarea uses a
placeholderfor hint text, but placeholders disappear when users start typing and aren't reliably announced by all screen readers as labels. Adding anaria-labelwould improve accessibility for assistive technology users.♿ Suggested accessibility improvement
<textarea value={comment} onChange={(e) => setComment(e.target.value)} placeholder="What was missing or unclear? (optional)" + aria-label="Optional feedback comment" rows={3} className="w-full resize-none rounded-md border border-fd-border bg-fd-background px-3 py-2 text-sm text-fd-foreground placeholder:text-fd-muted-foreground focus:outline-none focus:ring-2 focus:ring-fd-ring" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/components/page-feedback.tsx` around lines 101 - 107, The textarea in the PageFeedback component currently only uses a placeholder which is not a reliable accessible label; update the textarea element (the one using value={comment} and onChange={(e) => setComment(e.target.value)}) to include an accessible label by adding either an aria-label (e.g., aria-label="Feedback comment") or aria-labelledby pointing to a visible <label> element; ensure the label text matches the placeholder intent ("What was missing or unclear? (optional)") so screen readers receive the same hint.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/docs/src/components/page-feedback.tsx`:
- Around line 101-107: The textarea in the PageFeedback component currently only
uses a placeholder which is not a reliable accessible label; update the textarea
element (the one using value={comment} and onChange={(e) =>
setComment(e.target.value)}) to include an accessible label by adding either an
aria-label (e.g., aria-label="Feedback comment") or aria-labelledby pointing to
a visible <label> element; ensure the label text matches the placeholder intent
("What was missing or unclear? (optional)") so screen readers receive the same
hint.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 4dc18de0-5a8c-4173-9855-f59ac9336087
📒 Files selected for processing (1)
apps/docs/src/components/page-feedback.tsx
Summary
docs:page_feedback) and persisted in localStorage to avoid re-promptingLinear
https://linear.app/prisma-company/issue/DR-7574/docs-add-new-widget
Test plan
docs:page_feedbackfires with path, vote, and commentUI changes
posthog-review-widget.mov
Summary by CodeRabbit