Skip to content

feat (section): Add and Fixed animated pricing cards components#447

Open
KeenIsHere wants to merge 16 commits intocodse:mainfrom
KeenIsHere:feat/animated-pricing-cards
Open

feat (section): Add and Fixed animated pricing cards components#447
KeenIsHere wants to merge 16 commits intocodse:mainfrom
KeenIsHere:feat/animated-pricing-cards

Conversation

@KeenIsHere
Copy link
Copy Markdown

@KeenIsHere KeenIsHere commented Apr 26, 2026

Summary

Introduced a premium Animated Pricing Cards section designed for modern SaaS and AI landing pages. The component focuses on clean layout, subtle motion, and strong visual hierarchy, making it suitable for real-world product integrations as well as demo showcases.


image

Changes

  • Implemented a fully responsive pricing cards section (3-column → 1-column layout)
  • Added smooth hover lift interaction using transform-based animation for optimal performance
  • Highlighted the primary (featured) plan for better visual emphasis
  • Ensured accessible semantic structure using appropriate HTML elements
  • Integrated keyboard focus states for improved usability
  • Added default pricing data for immediate usability (copy-paste ready)
  • Created a Storybook story with full-width preview support
  • Added complete MDX documentation with usage examples, features, and accessibility notes

QA

  • Verified responsiveness across mobile, tablet, and desktop breakpoints
  • Ensured animations are smooth and GPU-optimized (transform + opacity only)
  • Tested hover and focus interactions for both mouse and keyboard users
  • Confirmed dark mode compatibility using design tokens
  • Checked reduced motion support for accessibility preferences
  • Ran lint checks and ensured no console warnings or errors
  • Validated component renders correctly with default props (no configuration required)

Notes

This component is designed to be production-ready, reusable, and easy to customize, aligning with Animata’s goal of providing high-quality, copy-paste-friendly UI building blocks.

Summary by CodeRabbit

  • New Features

    • Dropdown Menu: keyboard navigation (Arrow Up/Down, Enter, Escape), reduced‑motion support, smooth animations, left/right alignment, item icons, customizable trigger label
    • Animated Pricing Cards: responsive three‑tier layout, customizable plans with highlights, viewport entry animations, interactive CTA scaling
  • Documentation

    • Added docs and Storybook previews for both components, with example stories and usage notes

Copilot AI review requested due to automatic review settings April 26, 2026 11:22
@KeenIsHere KeenIsHere temporarily deployed to preview-deployment April 26, 2026 11:22 — with GitHub Actions Inactive
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

Adds two new UI components (DropdownMenu, AnimatedPricingCards) with Storybook stories and documentation; implements keyboard, click-outside, and motion behaviors for the dropdown and viewport-staggered entry/hover scaling for pricing cards; updates Storybook config, development script to use concurrently, and Storybook dev URL.

Changes

Cohort / File(s) Summary
DropdownMenu Component & Types
animata/navigation/dropdown-menu.tsx
New client component exporting MenuItem, DropdownMenuProps, and default DropdownMenu with open/close state, keyboard navigation (ArrowUp/ArrowDown/Enter/Escape), click-outside handling, left/right alignment, and Framer Motion entry/exit honoring reduced-motion.
DropdownMenu Stories & Docs
animata/navigation/dropdown-menu.stories.tsx, content/docs/navigation/dropdown-menu.mdx
Adds Storybook meta and Primary/RightAlign stories demonstrating items, align, and triggerLabel; docs page with usage, props table, and accessibility notes.
AnimatedPricingCards Component & Types
animata/section/animated-pricing-cards.tsx
New client component exporting PricingPlan, AnimatedPricingCardsProps, and default AnimatedPricingCards rendering responsive three-column pricing cards with viewport-triggered fade/slide animations, CTA hover/tap scaling, highlighted badge support, and default plan fallback.
AnimatedPricingCards Stories & Docs
animata/section/animated-pricing-cards.stories.tsx, content/docs/section/animated-pricing-cards.mdx
Adds Storybook meta and Primary/CustomPlans stories; docs with usage, prop/plan interface, animation details, accessibility and styling notes.
Storybook Config
.storybook/main.ts
Sets framework.options.nextConfigPath: "./next.config.mjs" and adds a webpackFinal hook that maps config.plugins and detects plugins by constructor.name (e.g., ProgressPlugin).
Local Dev Scripts / Env
package.json, .env.development
Replaces shell-based parallel dev orchestration with concurrently in dev script and adds concurrently to devDependencies; updates NEXT_PUBLIC_STORYBOOK_URL from http://localhost:6006 to http://localhost:6007.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • hari
  • sudhashrestha

Poem

🐰 I hopped through code with nimble paws,

New menus open with keyboard laws,
Pricing cards leap, then softly glide,
Stories and docs hop by my side,
Carrots for UI — a joyful stride! 🥕✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title mentions 'Add and Fixed animated pricing cards components' but the PR includes multiple changes beyond pricing cards: a new DropdownMenu component with stories and docs, Storybook configuration updates, environment variable changes, and build script modifications. Revise the title to accurately reflect all major changes, such as 'feat: Add animated pricing cards and dropdown menu components with Storybook improvements' or split into more focused PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share
Review rate limit: 6/8 reviews remaining, refill in 14 minutes and 38 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (7)
animata/section/animated-pricing-cards.tsx (1)

78-80: Consider a more robust React key.

plan.name is used as the list key. If consumers pass two plans with the same name, React will warn and reconciliation can misbehave. Combining with index (or requiring a unique id field) is safer.

♻️ Suggested tweak
-          {safePlans.map((plan, index) => (
-            <motion.article
-              key={plan.name}
+          {safePlans.map((plan, index) => (
+            <motion.article
+              key={`${plan.name}-${index}`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/section/animated-pricing-cards.tsx` around lines 78 - 80, The list
key for each item is currently using plan.name inside safePlans.map and passed
to the motion.article key prop; replace this fragile key with a more robust
unique identifier (e.g., use a dedicated id property on plan or combine
plan.name with the loop index like `${plan.name}-${index}`) so duplicate names
don't break React reconciliation, and update any relevant prop or type
expectations to require/accept a unique id if you choose that approach.
animata/section/animated-pricing-cards.stories.tsx (1)

18-74: Optional: hoist the render wrapper to remove duplication.

Primary and CustomPlans use an identical render wrapper. Consider extracting it (or moving the wrapper into meta.render) so each story only needs to override args.

♻️ Suggested cleanup
 const meta = {
   title: "Section/Animated Pricing Cards",
   component: AnimatedPricingCards,
   parameters: {
     layout: "fullscreen",
   },
   tags: ["autodocs"],
+  render: (args) => (
+    <div className="full-content w-full bg-background">
+      <AnimatedPricingCards {...args} />
+    </div>
+  ),
 } satisfies Meta<typeof AnimatedPricingCards>;
@@
-export const Primary: Story = {
-  args: {},
-  render: (args: AnimatedPricingCardsProps) => (
-    <div className="full-content w-full bg-background">
-      <AnimatedPricingCards {...args} />
-    </div>
-  ),
-};
+export const Primary: Story = {
+  args: {},
+};
@@
-  render: (args: AnimatedPricingCardsProps) => (
-    <div className="full-content w-full bg-background">
-      <AnimatedPricingCards {...args} />
-    </div>
-  ),
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/section/animated-pricing-cards.stories.tsx` around lines 18 - 74,
Primary and CustomPlans both duplicate the same render wrapper around
AnimatedPricingCards; hoist that wrapper into a shared place by moving the JSX
into meta.render (or extracting a helper render function) so stories only supply
args. Update the storybook export so meta.render returns <div
className="full-content w-full bg-background"><AnimatedPricingCards {...args}
/></div>, then remove the render implementations from Primary and CustomPlans
and leave just their args.
content/docs/navigation/dropdown-menu.mdx (1)

23-25: Accessibility section is too sparse for what the component advertises.

The PR description and component implementation tout full keyboard support (ArrowUp/Down cycle, Enter to activate, Escape to close + restore focus to trigger), reduced-motion compliance, and ARIA attributes. The docs reduce all of that to one sentence. Consider documenting the actual keymap and ARIA roles so consumers can verify expected behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/navigation/dropdown-menu.mdx` around lines 23 - 25, Expand the
Accessibility section for the DropdownMenu component to list the supported
keyboard interactions, ARIA roles/states, focus behavior, and reduced-motion
handling; specifically document the ArrowUp/ArrowDown cycling behavior,
Enter/Space activation, Escape to close and restore focus to the trigger,
Home/End if supported, any typeahead behavior, the roles used (e.g.,
role="menu"/"menuitem" or aria-haspopup/aria-expanded on the trigger), and
mention that animations respect prefers-reduced-motion — update the DropdownMenu
docs to include these explicit keymap and ARIA details so consumers can verify
expected behavior.
animata/navigation/dropdown-menu.tsx (3)

113-125: Arrow icon path is a full-length up arrow, not a chevron.

The SVG path draws a full down/up arrow (with shaft) rather than the conventional chevron-down used for dropdown indicators. Functionally fine, but visually unusual for a menu trigger. Consider replacing with a simple chevron path (e.g. M19 9l-7 7-7-7) or lucide-react's ChevronDown (already a dependency in the stories).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/navigation/dropdown-menu.tsx` around lines 113 - 125, The SVG used in
dropdown-menu.tsx renders a full-length arrow shaft ("d=\"M19 14l-7 7m0 0l-7-7m7
7V3\"") instead of a chevron; replace the path with a chevron path (for example
"M19 9l-7 7-7-7") or swap the inline SVG for the project's existing ChevronDown
icon from lucide-react (import and render ChevronDown in place of the current
<svg> in the DropdownMenu trigger) so the visual matches a standard dropdown
chevron.

35-39: prefersReducedMotion should be state, not a ref.

The ref is mutated in useEffect but read during render at Line 87 — mutating a ref does not trigger re-render, so the value is only "correct" because the menu starts closed and the effect runs before the first open. It also won't react to runtime changes of the user's motion preference. Prefer useState plus a change listener on the MediaQueryList:

♻️ Proposed refactor
-  const prefersReducedMotion = useRef(false);
-
-  useEffect(() => {
-    prefersReducedMotion.current = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
-  }, []);
+  const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
+
+  useEffect(() => {
+    const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
+    setPrefersReducedMotion(mql.matches);
+    const onChange = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches);
+    mql.addEventListener("change", onChange);
+    return () => mql.removeEventListener("change", onChange);
+  }, []);
@@
-  const animationProps = prefersReducedMotion.current
+  const animationProps = prefersReducedMotion
     ? {}
     : {
         initial: { opacity: 0, translateY: -8 },
         animate: { opacity: 1, translateY: 0 },
         exit: { opacity: 0, translateY: -8 },
       };

Also applies to: 87-93

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/navigation/dropdown-menu.tsx` around lines 35 - 39, Replace the
prefersReducedMotion ref with React state: use useState<boolean> for
prefersReducedMotion (instead of useRef) and initialize it from
window.matchMedia("(prefers-reduced-motion: reduce)").matches inside a
useEffect; attach a MediaQueryList change listener that updates the state when
the preference changes, and remove that listener in the effect cleanup. Update
any code that reads prefersReducedMotion (the render logic that currently reads
prefersReducedMotion.current) to read the state variable directly so changes
trigger re-renders.

47-67: Consider scope and focus management for the Enter key handler.

The handler listens globally on window and triggers items[selectedIndex]?.onClick?.() regardless of which menu item has DOM focus. If a user manually tabs to a different menu item than the one highlighted via arrow keys, pressing Enter will fire the wrong item's onClick handler. Consider either: (1) preventing menu items from receiving tab focus with tabIndex={-1}, (2) syncing selectedIndex with actual DOM focus state, or (3) removing the manual Enter handler and letting the focused button handle it natively.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/navigation/dropdown-menu.tsx` around lines 47 - 67, The Enter branch
in handleKeyDown triggers items[selectedIndex]?.onClick regardless of actual DOM
focus and should be removed so the focused menu item handles activation
natively; delete the `else if (e.key === "Enter") { ... }` block from
handleKeyDown, ensure each menu item element is a native focusable control
(button/a) that invokes its onClick, and if you want to keep keyboard-only
selection, alternatively set menu item elements to tabIndex={-1} and keep
selection-only navigation via selectedIndex—choose one approach and update the
code around handleKeyDown, selectedIndex, items, and setIsOpen accordingly.
animata/navigation/dropdown-menu.stories.tsx (1)

28-62: LGTM — duplication is minor and acceptable for stories.

Both stories duplicate the same items array; for two stories that's fine, but if more variants are added consider hoisting to a module-level sampleItems constant. Otherwise the meta typing, argTypes, and render wrappers all look correct.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/navigation/dropdown-menu.stories.tsx` around lines 28 - 62, Hoist the
duplicated items arrays used by the Primary and RightAlign stories into a shared
module-level constant (e.g., sampleItems) and have both story args reference
that constant instead of inline arrays; update the args for Primary and
RightAlign to use sampleItems and keep the existing render wrappers and props
passed to DropdownMenu unchanged so behavior and typings (Story, argTypes)
remain intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@animata/navigation/dropdown-menu.tsx`:
- Around line 47-67: The arrow-key handler currently updates selectedIndex
visually but doesn't move DOM focus; fix by creating an array of refs for the
menu item buttons (e.g., menuItemRefs) and, in an effect that runs when
selectedIndex or isOpen changes, call
menuItemRefs[selectedIndex]?.current?.focus() when the menu is open so the
corresponding <button role="menuitem"> receives focus; update the Enter handling
in handleKeyDown to rely on the focused button (or call
menuItemRefs[selectedIndex]?.current?.click()) instead of directly invoking
items[selectedIndex]?.onClick, and ensure you create/cleanup refs and keep
triggerRef focus behavior on Escape (triggerRef.current?.focus()); apply the
same ref/focus pattern to the other menu instance referenced similarly in this
file.

In `@animata/section/animated-pricing-cards.tsx`:
- Around line 120-130: The checkmark SVG in animated-pricing-cards.tsx is
decorative and should be hidden from assistive tech; update the SVG element (the
<svg> wrapping the checkmark path with className "h-5 w-5 shrink-0
text-primary") to include aria-hidden="true" and focusable="false" so screen
readers ignore it (do not add role="img").
- Around line 136-149: The Framer Motion props on motion.button
(whileHover/whileTap) still run for users with prefers-reduced-motion because
the Tailwind motion-reduce: variant only affects CSS; fix by importing
useReducedMotion from "framer-motion" (or "motion/react" per project) inside the
component that renders the motion.button, call useReducedMotion() (e.g., const
reduceMotion = useReducedMotion()), and conditionally pass the whileHover and
whileTap props only when reduceMotion is false—i.e., build an props object (or
inline conditional) to omit whileHover/whileTap for reduced motion users while
keeping the existing className and plan.ctaText handling in the
AnimatedPricingCards component/motion.button render.
- Around line 79-93: The Tailwind transform utilities (lg:scale-105,
motion-safe:hover:-translate-y-2) are being overridden by Framer Motion's inline
transform on motion.article; remove those transform classes from className and
instead express them via Motion props: add a conditional animate or whileInView
scale when plan.highlighted (e.g., animate={{ scale: plan.highlighted ? 1.05 : 1
}} or include scale in whileInView) and replace the hover translate with a
whileHover prop that applies y: -8 (or equivalent); gate the whileHover by using
useReducedMotion() from "motion/react" so you only set whileHover when reduced
motion is false. Ensure className retains non-transform utilities and refer to
motion.article, whileInView, animate/whileHover, useReducedMotion, and
plan.highlighted when making the changes.

In `@content/docs/navigation/dropdown-menu.mdx`:
- Around line 17-21: The docs table incorrectly states the items prop default is
[] but the component dropdown-menu.tsx defines a 4-entry defaultItems array
(Profile, Settings, Help, Sign Out) used when items is omitted; update the docs
in content/docs/navigation/dropdown-menu.mdx to show the actual default (e.g.,
defaultItems — or list the four default entries) for the items prop and mention
that dropdown-menu.tsx uses defaultItems as the fallback to keep docs in sync
with the DropdownMenu component.
- Around line 7-13: Update the Usage section to include the shadcn registry
install command using the required registry URL format for this component; add a
line with the npx shadcn@latest add
https://animata.design/r/navigation/dropdown-menu.json command before the import
example so users can install the DropdownMenu from the registry, then keep the
existing import of DropdownMenu and usage example unchanged.

In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 107-113: Update the "Browser Support" section so it only lists
actual browser features (e.g., CSS Grid and Flexbox, CSS Custom Properties,
ES2020+ JavaScript) and remove "Framer Motion" from that list; instead add a
note elsewhere (or a new "Runtime dependencies" or "Requirements" line) stating
the component depends on the Motion library bundled with the app and imports
from "motion/react" (not the browser), so browsers themselves need only the
listed language and CSS features.
- Line 56: Update the wording that currently says "Middle card features a 'Most
Popular' badge and scale effect" to clarify that the badge/scale is applied to
any plan with highlighted: true rather than by position; reference the prop/flag
highlighted: true and the plan object so copy explains "The card with
highlighted: true shows the 'Most Popular' badge and scale effect" instead of
implying it's always the middle card.

---

Nitpick comments:
In `@animata/navigation/dropdown-menu.stories.tsx`:
- Around line 28-62: Hoist the duplicated items arrays used by the Primary and
RightAlign stories into a shared module-level constant (e.g., sampleItems) and
have both story args reference that constant instead of inline arrays; update
the args for Primary and RightAlign to use sampleItems and keep the existing
render wrappers and props passed to DropdownMenu unchanged so behavior and
typings (Story, argTypes) remain intact.

In `@animata/navigation/dropdown-menu.tsx`:
- Around line 113-125: The SVG used in dropdown-menu.tsx renders a full-length
arrow shaft ("d=\"M19 14l-7 7m0 0l-7-7m7 7V3\"") instead of a chevron; replace
the path with a chevron path (for example "M19 9l-7 7-7-7") or swap the inline
SVG for the project's existing ChevronDown icon from lucide-react (import and
render ChevronDown in place of the current <svg> in the DropdownMenu trigger) so
the visual matches a standard dropdown chevron.
- Around line 35-39: Replace the prefersReducedMotion ref with React state: use
useState<boolean> for prefersReducedMotion (instead of useRef) and initialize it
from window.matchMedia("(prefers-reduced-motion: reduce)").matches inside a
useEffect; attach a MediaQueryList change listener that updates the state when
the preference changes, and remove that listener in the effect cleanup. Update
any code that reads prefersReducedMotion (the render logic that currently reads
prefersReducedMotion.current) to read the state variable directly so changes
trigger re-renders.
- Around line 47-67: The Enter branch in handleKeyDown triggers
items[selectedIndex]?.onClick regardless of actual DOM focus and should be
removed so the focused menu item handles activation natively; delete the `else
if (e.key === "Enter") { ... }` block from handleKeyDown, ensure each menu item
element is a native focusable control (button/a) that invokes its onClick, and
if you want to keep keyboard-only selection, alternatively set menu item
elements to tabIndex={-1} and keep selection-only navigation via
selectedIndex—choose one approach and update the code around handleKeyDown,
selectedIndex, items, and setIsOpen accordingly.

In `@animata/section/animated-pricing-cards.stories.tsx`:
- Around line 18-74: Primary and CustomPlans both duplicate the same render
wrapper around AnimatedPricingCards; hoist that wrapper into a shared place by
moving the JSX into meta.render (or extracting a helper render function) so
stories only supply args. Update the storybook export so meta.render returns
<div className="full-content w-full bg-background"><AnimatedPricingCards
{...args} /></div>, then remove the render implementations from Primary and
CustomPlans and leave just their args.

In `@animata/section/animated-pricing-cards.tsx`:
- Around line 78-80: The list key for each item is currently using plan.name
inside safePlans.map and passed to the motion.article key prop; replace this
fragile key with a more robust unique identifier (e.g., use a dedicated id
property on plan or combine plan.name with the loop index like
`${plan.name}-${index}`) so duplicate names don't break React reconciliation,
and update any relevant prop or type expectations to require/accept a unique id
if you choose that approach.

In `@content/docs/navigation/dropdown-menu.mdx`:
- Around line 23-25: Expand the Accessibility section for the DropdownMenu
component to list the supported keyboard interactions, ARIA roles/states, focus
behavior, and reduced-motion handling; specifically document the
ArrowUp/ArrowDown cycling behavior, Enter/Space activation, Escape to close and
restore focus to the trigger, Home/End if supported, any typeahead behavior, the
roles used (e.g., role="menu"/"menuitem" or aria-haspopup/aria-expanded on the
trigger), and mention that animations respect prefers-reduced-motion — update
the DropdownMenu docs to include these explicit keymap and ARIA details so
consumers can verify expected behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66f242ba-068c-46eb-9fef-e06a3cb985b8

📥 Commits

Reviewing files that changed from the base of the PR and between da9d7b2 and 6c39e4b.

📒 Files selected for processing (6)
  • animata/navigation/dropdown-menu.stories.tsx
  • animata/navigation/dropdown-menu.tsx
  • animata/section/animated-pricing-cards.stories.tsx
  • animata/section/animated-pricing-cards.tsx
  • content/docs/navigation/dropdown-menu.mdx
  • content/docs/section/animated-pricing-cards.mdx

Comment on lines +47 to +67
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "ArrowDown") {
e.preventDefault();
setSelectedIndex((prev) => (prev + 1) % items.length);
} else if (e.key === "ArrowUp") {
e.preventDefault();
setSelectedIndex((prev) => (prev - 1 + items.length) % items.length);
} else if (e.key === "Enter") {
e.preventDefault();
items[selectedIndex]?.onClick?.();
setIsOpen(false);
} else if (e.key === "Escape") {
e.preventDefault();
setIsOpen(false);
triggerRef.current?.focus();
}
};

window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [isOpen, selectedIndex, items]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Arrow keys update visual selection but do not move DOM focus — a11y gap.

Arrow keys mutate selectedIndex (visual highlight only) while DOM focus remains on the trigger button. Screen readers won't announce the active menuitem, and Tab order isn't synchronized with the highlighted row. Since the docs (dropdown-menu.mdx) advertise full keyboard navigation, consider focusing the matching <button role="menuitem"> when selectedIndex changes (e.g., via an array of refs and .focus() in an effect), and let Enter rely on the focused button.

Also applies to: 141-162

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/navigation/dropdown-menu.tsx` around lines 47 - 67, The arrow-key
handler currently updates selectedIndex visually but doesn't move DOM focus; fix
by creating an array of refs for the menu item buttons (e.g., menuItemRefs) and,
in an effect that runs when selectedIndex or isOpen changes, call
menuItemRefs[selectedIndex]?.current?.focus() when the menu is open so the
corresponding <button role="menuitem"> receives focus; update the Enter handling
in handleKeyDown to rely on the focused button (or call
menuItemRefs[selectedIndex]?.current?.click()) instead of directly invoking
items[selectedIndex]?.onClick, and ensure you create/cleanup refs and keep
triggerRef focus behavior on Escape (triggerRef.current?.focus()); apply the
same ref/focus pattern to the other menu instance referenced similarly in this
file.

Comment on lines +79 to +93
<motion.article
key={plan.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1, duration: 0.4 }}
viewport={{ once: true, margin: "-100px" }}
className={cn(
"group relative flex flex-col rounded-2xl border transition-all duration-300",
"motion-safe:hover:-translate-y-2",
"bg-background p-6 sm:p-8 lg:p-10",
plan.highlighted
? "border-primary shadow-lg lg:scale-105"
: "border-border shadow-sm motion-safe:hover:shadow-md",
)}
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Does Framer Motion / motion v12 set transform via inline style and override Tailwind transform utility classes like hover:-translate-y-2andlg:scale-105?

💡 Result:

Yes, Framer Motion (now Motion) v12 sets transform properties via inline styles, which override Tailwind CSS transform utility classes such as hover:-translate-y-2 and lg:scale-105. Motion animates by applying inline styles or native browser animations, both of which override Tailwind CSS classes. This is by design, as the libraries complement each other: Tailwind for static/responsive styling, Motion for animations. Tailwind transform utilities (e.g., translate, scale) generate CSS transform properties with higher specificity from classes, but inline styles applied by Motion during/after animation have higher CSS specificity and take precedence. Once Motion animates a transform property (e.g., via animate={{ scale: 1.05 }} or whileHover), it persists the final inline style value, preventing Tailwind's CSS-declared transforms (including pseudo-class like hover or media-query like lg:) from applying. Evidence from official Motion docs confirms inline styles override classes. Community reports (Stack Overflow, GitHub issues) consistently show Tailwind hover transforms failing on Motion elements, requiring !important variants (e.g., hover:!scale-110) as workarounds, confirming the override behavior. No v12-specific changes alter this core mechanism; upgrade guides mention transform optimizations but retain inline style application.

Citations:


Tailwind transforms will be overridden by Motion's inline transform style.

Motion applies transform via inline style attribute, which has higher CSS specificity than Tailwind utility classes. Once motion.article animates, the inline transform persists, preventing:

  • lg:scale-105 from taking effect on the highlighted card
  • motion-safe:hover:-translate-y-2 from applying on hover

Move these into Motion's animation props instead:

♻️ Suggested fix
             <motion.article
               key={plan.name}
               initial={{ opacity: 0, y: 20 }}
-              whileInView={{ opacity: 1, y: 0 }}
+              whileInView={{ opacity: 1, y: 0, scale: plan.highlighted ? 1.05 : 1 }}
+              whileHover={{ y: -8 }}
               transition={{ delay: index * 0.1, duration: 0.4 }}
               viewport={{ once: true, margin: "-100px" }}
               className={cn(
                 "group relative flex flex-col rounded-2xl border transition-all duration-300",
-                "motion-safe:hover:-translate-y-2",
                 "bg-background p-6 sm:p-8 lg:p-10",
                 plan.highlighted
-                  ? "border-primary shadow-lg lg:scale-105"
+                  ? "border-primary shadow-lg"
                   : "border-border shadow-sm motion-safe:hover:shadow-md",
               )}
             >

Gate whileHover with useReducedMotion() from motion/react to respect prefers-reduced-motion.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<motion.article
key={plan.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1, duration: 0.4 }}
viewport={{ once: true, margin: "-100px" }}
className={cn(
"group relative flex flex-col rounded-2xl border transition-all duration-300",
"motion-safe:hover:-translate-y-2",
"bg-background p-6 sm:p-8 lg:p-10",
plan.highlighted
? "border-primary shadow-lg lg:scale-105"
: "border-border shadow-sm motion-safe:hover:shadow-md",
)}
>
<motion.article
key={plan.name}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0, scale: plan.highlighted ? 1.05 : 1 }}
whileHover={{ y: -8 }}
transition={{ delay: index * 0.1, duration: 0.4 }}
viewport={{ once: true, margin: "-100px" }}
className={cn(
"group relative flex flex-col rounded-2xl border transition-all duration-300",
"bg-background p-6 sm:p-8 lg:p-10",
plan.highlighted
? "border-primary shadow-lg"
: "border-border shadow-sm motion-safe:hover:shadow-md",
)}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/section/animated-pricing-cards.tsx` around lines 79 - 93, The
Tailwind transform utilities (lg:scale-105, motion-safe:hover:-translate-y-2)
are being overridden by Framer Motion's inline transform on motion.article;
remove those transform classes from className and instead express them via
Motion props: add a conditional animate or whileInView scale when
plan.highlighted (e.g., animate={{ scale: plan.highlighted ? 1.05 : 1 }} or
include scale in whileInView) and replace the hover translate with a whileHover
prop that applies y: -8 (or equivalent); gate the whileHover by using
useReducedMotion() from "motion/react" so you only set whileHover when reduced
motion is false. Ensure className retains non-transform utilities and refer to
motion.article, whileInView, animate/whileHover, useReducedMotion, and
plan.highlighted when making the changes.

Comment thread animata/section/animated-pricing-cards.tsx
Comment on lines +136 to +149
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
className={cn(
"h-11 w-full rounded-lg font-semibold transition-colors duration-200",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"motion-reduce:hover:scale-100",
plan.highlighted
? "bg-primary text-primary-foreground hover:bg-primary/90"
: "border border-border text-foreground hover:bg-muted",
)}
>
{plan.ctaText || "Get Started"}
</motion.button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

motion-reduce:hover:scale-100 doesn't disable Motion's whileHover/whileTap.

Tailwind's motion-reduce: variant only neutralizes CSS-based transforms; it has no effect on Framer Motion's whileHover/whileTap, which animate via inline transform. So this button still scales for users with prefers-reduced-motion, contradicting the docs' "motion handling".

Use useReducedMotion() from motion/react and conditionally drop the props:

♻️ Suggested fix
-import { motion } from "motion/react";
+import { motion, useReducedMotion } from "motion/react";
@@
 export default function AnimatedPricingCards({ plans = defaultPlans }: AnimatedPricingCardsProps) {
   const safePlans = Array.isArray(plans) ? plans : defaultPlans;
+  const prefersReducedMotion = useReducedMotion();
@@
               <motion.button
-                whileHover={{ scale: 1.02 }}
-                whileTap={{ scale: 0.98 }}
+                whileHover={prefersReducedMotion ? undefined : { scale: 1.02 }}
+                whileTap={prefersReducedMotion ? undefined : { scale: 0.98 }}
                 className={cn(
                   "h-11 w-full rounded-lg font-semibold transition-colors duration-200",
                   "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
-                  "motion-reduce:hover:scale-100",
                   plan.highlighted
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@animata/section/animated-pricing-cards.tsx` around lines 136 - 149, The
Framer Motion props on motion.button (whileHover/whileTap) still run for users
with prefers-reduced-motion because the Tailwind motion-reduce: variant only
affects CSS; fix by importing useReducedMotion from "framer-motion" (or
"motion/react" per project) inside the component that renders the motion.button,
call useReducedMotion() (e.g., const reduceMotion = useReducedMotion()), and
conditionally pass the whileHover and whileTap props only when reduceMotion is
false—i.e., build an props object (or inline conditional) to omit
whileHover/whileTap for reduced motion users while keeping the existing
className and plan.ctaText handling in the AnimatedPricingCards
component/motion.button render.

Comment on lines +7 to +13
## Usage

Copy the component into your project and import it.

```typescript
import DropdownMenu from "@/animata/navigation/dropdown-menu";
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Missing shadcn registry installation snippet.

The Usage section only suggests copying the component. Per repo convention, docs should reference the shadcn registry URL so users can install via the registry. As per coding guidelines: "Use shadcn registry URL format https://animata.design/r/{category}/{name}.json in docs/changelog — never bare npx shadcn add component-name".

📝 Suggested addition
 ## Usage

-Copy the component into your project and import it.
+Install via the registry:
+
+```bash
+npx shadcn@latest add https://animata.design/r/navigation/dropdown-menu.json
+```
+
+Then import and use:

 ```typescript
 import DropdownMenu from "@/animata/navigation/dropdown-menu";
 ```

As per coding guidelines: **/*.mdx: Use shadcn registry URL format https://animata.design/r/{category}/{name}.json in docs/changelog — never bare npx shadcn add component-name.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Usage
Copy the component into your project and import it.
```typescript
import DropdownMenu from "@/animata/navigation/dropdown-menu";
```
## Usage
Install via the registry:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/navigation/dropdown-menu.mdx` around lines 7 - 13, Update the
Usage section to include the shadcn registry install command using the required
registry URL format for this component; add a line with the npx shadcn@latest
add https://animata.design/r/navigation/dropdown-menu.json command before the
import example so users can install the DropdownMenu from the registry, then
keep the existing import of DropdownMenu and usage example unchanged.

Comment on lines +17 to +21
| Prop | Type | Default | Description |
|---|---|---|---|
| items | MenuItem[] | [] | Array of menu items |
| triggerLabel | string | "Options" | Button label |
| align | "left" \| "right" | "left" | Dropdown alignment |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

items default does not match the implementation.

Docs list the default as [], but dropdown-menu.tsx (Line 19-24, 27) defaults items to a 4-entry defaultItems array (Profile, Settings, Help, Sign Out). Update the table to reflect the actual default so consumers aren't surprised by populated content when they omit the prop.

📝 Proposed fix
-| items | MenuItem[] | [] | Array of menu items |
+| items | MenuItem[] | `defaultItems` (Profile, Settings, Help, Sign Out) | Array of menu items |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Prop | Type | Default | Description |
|---|---|---|---|
| items | MenuItem[] | [] | Array of menu items |
| triggerLabel | string | "Options" | Button label |
| align | "left" \| "right" | "left" | Dropdown alignment |
| Prop | Type | Default | Description |
|---|---|---|---|
| items | MenuItem[] | `defaultItems` (Profile, Settings, Help, Sign Out) | Array of menu items |
| triggerLabel | string | "Options" | Button label |
| align | "left" \| "right" | "left" | Dropdown alignment |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/navigation/dropdown-menu.mdx` around lines 17 - 21, The docs
table incorrectly states the items prop default is [] but the component
dropdown-menu.tsx defines a 4-entry defaultItems array (Profile, Settings, Help,
Sign Out) used when items is omitted; update the docs in
content/docs/navigation/dropdown-menu.mdx to show the actual default (e.g.,
defaultItems — or list the four default entries) for the items prop and mention
that dropdown-menu.tsx uses defaultItems as the fallback to keep docs in sync
with the DropdownMenu component.

Comment thread content/docs/section/animated-pricing-cards.mdx Outdated
Comment on lines +107 to +113
## Browser Support

Works in all modern browsers that support:
- CSS Grid and Flexbox
- CSS Custom Properties
- Framer Motion
- ES2020+ JavaScript
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Framer Motion is a runtime dependency, not a browser feature.

The Browser Support list mixes browser capabilities (Grid, Flexbox, CSS variables, ES2020+) with Framer Motion, which is a JS library bundled with the app — not something the browser needs to "support". Also, the component imports from motion/react (the renamed Motion package), so referring to it as Framer Motion is doubly inaccurate.

📝 Suggested edit
 Works in all modern browsers that support:
 - CSS Grid and Flexbox
 - CSS Custom Properties
-- Framer Motion
 - ES2020+ JavaScript
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Browser Support
Works in all modern browsers that support:
- CSS Grid and Flexbox
- CSS Custom Properties
- Framer Motion
- ES2020+ JavaScript
## Browser Support
Works in all modern browsers that support:
- CSS Grid and Flexbox
- CSS Custom Properties
- ES2020+ JavaScript
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/section/animated-pricing-cards.mdx` around lines 107 - 113,
Update the "Browser Support" section so it only lists actual browser features
(e.g., CSS Grid and Flexbox, CSS Custom Properties, ES2020+ JavaScript) and
remove "Framer Motion" from that list; instead add a note elsewhere (or a new
"Runtime dependencies" or "Requirements" line) stating the component depends on
the Motion library bundled with the app and imports from "motion/react" (not the
browser), so browsers themselves need only the listed language and CSS features.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions
Copy link
Copy Markdown

🚀 Preview deployed to: https://e7646919.animata.pages.dev

@hari
Copy link
Copy Markdown
Contributor

hari commented Apr 27, 2026

@KeenIsHere, here are a few things to fix/consider:

  1. Ensure that all components are responsive.
  2. Really love the docs page, but you’ve missed the installation instructions. To generate the documentation with installation instructions, use the command yarn animata:new to create new components. Then, add additional instructions as you did.
  3. You’ve also included code from another branch or pull request here. When adding a new branch, make sure to create a new branch from the main branch.

Copy link
Copy Markdown
Contributor

@hari hari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my other comments.

---
title: Animated Pricing Cards
description: A responsive pricing section with smooth hover animations, "Most Popular" badge, and premium SaaS design.
author: AnimataContributor
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use your twitter handle

@KeenIsHere
Copy link
Copy Markdown
Author

@KeenIsHere, here are a few things to fix/consider:

  1. Ensure that all components are responsive.
  2. Really love the docs page, but you’ve missed the installation instructions. To generate the documentation with installation instructions, use the command yarn animata:new to create new components. Then, add additional instructions as you did.
  3. You’ve also included code from another branch or pull request here. When adding a new branch, make sure to create a new branch from the main branch.

@KeenIsHere KeenIsHere closed this Apr 27, 2026
@KeenIsHere KeenIsHere reopened this Apr 28, 2026
@KeenIsHere KeenIsHere temporarily deployed to preview-deployment April 28, 2026 11:35 — with GitHub Actions Inactive
@github-actions
Copy link
Copy Markdown

🚀 Preview deployed to: https://9d8772e0.animata.pages.dev

Move transforms to Motion props to avoid Tailwind overrides and respect prefers-reduced-motion.
…aders

Add aria-hidden and focusable=false to checkmark SVG for accessibility.
…on guide

- Clarify highlighted card is driven by highlighted prop, not position
- Remove Framer Motion from browser support (runtime dependency, not browser feature)
- Add installation instructions using yarn animata:new
- Update animation details to reflect Motion-based approach
- Replace Unix shell syntax (&, wait) with cross-platform concurrently
- Install concurrently package for parallel process management
- Update .storybook/main.ts with webpack configuration
- Add .env.storybook for font optimization settings
- Include comprehensive troubleshooting guide

This fixes yarn dev failures on Windows and provides workarounds for
Google Fonts network connectivity issues.
@KeenIsHere KeenIsHere requested a deployment to preview-deployment April 28, 2026 17:02 — with GitHub Actions Waiting
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.storybook/main.ts:
- Around line 13-29: The webpackFinal hook is a no-op: mapping config.plugins
and returning each plugin unchanged (including the ProgressPlugin) doesn't
suppress Google Fonts errors; either remove the entire webpackFinal block or
implement real suppression by mutating config.plugins (e.g., filter out or
replace the plugin that triggers Google Fonts loads) instead of the current
identity map. Locate webpackFinal and the config.plugins map and replace the map
with logic that filters out the specific plugin by constructor.name (or returns
a stubbed plugin) that causes Google Fonts errors (or simply delete the hook if
no suppression is needed) so the hook actually changes config.plugins rather
than leaving it unchanged.

In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 14-22: Update the Installation section to include the direct
registry URL install form alongside the existing yarn animata:new flow: add a
short sentence and an example install command using the shadcn registry URL
format (https://animata.design/r/{category}/{name}.json) so consumers can
install a generated component directly (e.g., show the registry URL with
placeholders for {category} and {name} and a corresponding yarn or curl command)
and ensure the docs avoid suggesting bare npx/shadcn add usage.
- Around line 101-106: The docs incorrectly state that motion handling uses the
useReducedMotion() hook; update content in animated-pricing-cards.mdx to reflect
the component implementation in animata/section/animated-pricing-cards.tsx by
replacing the reference to useReducedMotion() with that animations are
controlled via the motion-safe and motion-reduce CSS classes (e.g., mention
"motion-safe/motion-reduce classes" and that they are applied to the
cards/viewport animations) so the docs match the actual behavior.

In `@package.json`:
- Line 7: The dev script in package.json starts Storybook on port 6006 while
your .env.development exposes NEXT_PUBLIC_STORYBOOK_URL pointing to :6007,
causing preview links to 6007 to fail; update the "dev" script (the "dev" npm
script string in package.json that currently invokes "storybook dev -p 6006
--no-open --debug-webpack") to use the same port as NEXT_PUBLIC_STORYBOOK_URL
(e.g., change 6006 to 6007) or refactor the script to read the port from the env
var so Storybook and NEXT_PUBLIC_STORYBOOK_URL stay aligned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 490847db-3005-4eff-b2d2-550388b00ae7

📥 Commits

Reviewing files that changed from the base of the PR and between 6c39e4b and edbe9a7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • .env.development
  • .storybook/main.ts
  • animata/section/animated-pricing-cards.tsx
  • content/docs/section/animated-pricing-cards.mdx
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • .env.development
🚧 Files skipped from review as they are similar to previous changes (1)
  • animata/section/animated-pricing-cards.tsx

Comment thread .storybook/main.ts
Comment on lines +13 to +29
webpackFinal: async (config) => {
// Suppress Google Fonts loading errors during dev
if (config.plugins) {
config.plugins = config.plugins.map((plugin) => {
if (
plugin &&
typeof plugin === "object" &&
"constructor" in plugin &&
plugin.constructor.name === "ProgressPlugin"
) {
return plugin;
}
return plugin;
});
}
return config;
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
sed -n '13,29p' .storybook/main.ts
rg -n 'return plugin;|constructor.name === "ProgressPlugin"' .storybook/main.ts

Repository: codse/animata

Length of output: 617


webpackFinal is a no-op that does not suppress Google Fonts errors.

Both branches of the conditional on lines 21–25 return plugin unchanged. The map over config.plugins produces no mutations, so this hook adds misleading configuration without actually addressing the stated problem.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.storybook/main.ts around lines 13 - 29, The webpackFinal hook is a no-op:
mapping config.plugins and returning each plugin unchanged (including the
ProgressPlugin) doesn't suppress Google Fonts errors; either remove the entire
webpackFinal block or implement real suppression by mutating config.plugins
(e.g., filter out or replace the plugin that triggers Google Fonts loads)
instead of the current identity map. Locate webpackFinal and the config.plugins
map and replace the map with logic that filters out the specific plugin by
constructor.name (or returns a stubbed plugin) that causes Google Fonts errors
(or simply delete the hook if no suppression is needed) so the hook actually
changes config.plugins rather than leaving it unchanged.

Comment on lines +14 to +22
## Installation

To create and install this component, use the following command:

```bash
yarn animata:new
```

Then select the section category and follow the prompts to generate the component files.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add the direct registry URL install path here.

The install section only documents yarn animata:new. For MDX docs, this component should also expose the registry URL form so consumers can install it directly.

📝 Suggested doc update
 ## Installation

-To create and install this component, use the following command:
+Install directly from the registry with:
+
+`https://animata.design/r/section/animated-pricing-cards.json`
+
+If you prefer the guided generator flow, use:

 ```bash
 yarn animata:new
</details>

As per coding guidelines: `**/*.mdx`: Use shadcn registry URL format `https://animata.design/r/{category}/{name}.json` in docs/changelog — never bare `npx shadcn add component-name`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @content/docs/section/animated-pricing-cards.mdx around lines 14 - 22, Update
the Installation section to include the direct registry URL install form
alongside the existing yarn animata:new flow: add a short sentence and an
example install command using the shadcn registry URL format
(https://animata.design/r/{category}/{name}.json) so consumers can install a
generated component directly (e.g., show the registry URL with placeholders for
{category} and {name} and a corresponding yarn or curl command) and ensure the
docs avoid suggesting bare npx/shadcn add usage.


</details>

<!-- fingerprinting:phantom:medusa:ocelot:daf43c5a-171c-4553-a9a1-2f40e6cb0d3e -->

<!-- d98c2f50 -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +101 to +106
- **Stagger delay**: 100ms between cards on initial load
- **Hover effect**: 8px upward lift (y: -8) with smooth transition
- **Button hover**: Scale to 1.02 on hover for visual feedback
- **Button tap**: Scale to 0.98 on tap for mobile feedback
- **Viewport animation**: Triggers when cards enter viewport
- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
sed -n '1,170p' animata/section/animated-pricing-cards.tsx
rg -n 'useReducedMotion|motion-safe|motion-reduce' animata/section/animated-pricing-cards.tsx

Repository: codse/animata

Length of output: 5915


Update docs to match component implementation: use motion-safe/motion-reduce instead of useReducedMotion() hook.

Lines 101-106 incorrectly state that motion handling uses useReducedMotion(), but animata/section/animated-pricing-cards.tsx uses only motion-safe and motion-reduce CSS classes (lines 87, 91, 144).

📝 Suggested doc update
-- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook
+- **Motion handling**: Hover and interaction animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` classes
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Stagger delay**: 100ms between cards on initial load
- **Hover effect**: 8px upward lift (y: -8) with smooth transition
- **Button hover**: Scale to 1.02 on hover for visual feedback
- **Button tap**: Scale to 0.98 on tap for mobile feedback
- **Viewport animation**: Triggers when cards enter viewport
- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook
- **Stagger delay**: 100ms between cards on initial load
- **Hover effect**: 8px upward lift (y: -8) with smooth transition
- **Button hover**: Scale to 1.02 on hover for visual feedback
- **Button tap**: Scale to 0.98 on tap for mobile feedback
- **Viewport animation**: Triggers when cards enter viewport
- **Motion handling**: Hover and interaction animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` classes
🧰 Tools
🪛 LanguageTool

[grammar] ~101-~101: Ensure spelling is correct
Context: ...Animation Details - Stagger delay: 100ms between cards on initial load - **Hover...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~102-~102: Ensure spelling is correct
Context: ...rds on initial load - Hover effect: 8px upward lift (y: -8) with smooth transit...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/section/animated-pricing-cards.mdx` around lines 101 - 106, The
docs incorrectly state that motion handling uses the useReducedMotion() hook;
update content in animated-pricing-cards.mdx to reflect the component
implementation in animata/section/animated-pricing-cards.tsx by replacing the
reference to useReducedMotion() with that animations are controlled via the
motion-safe and motion-reduce CSS classes (e.g., mention
"motion-safe/motion-reduce classes" and that they are applied to the
cards/viewport animations) so the docs match the actual behavior.

Comment thread package.json
@KeenIsHere KeenIsHere requested a review from hari April 29, 2026 03:27
@KeenIsHere KeenIsHere requested a deployment to preview-deployment April 29, 2026 04:18 — with GitHub Actions Waiting
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
content/docs/section/animated-pricing-cards.mdx (2)

16-22: ⚠️ Potential issue | 🟡 Minor

Add the direct registry install URL to the Installation section.

Right now this only documents the generator flow. Please also include the direct registry URL format for this component.

Suggested doc patch
 ## Installation
 
-To create and install this component, use the following command:
+Install directly from the registry:
+
+`https://animata.design/r/section/animated-pricing-cards.json`
+
+Or use the guided generator flow:
 
 ```bash
 yarn animata:new

Then select the section category and follow the prompts to generate the component files.

</details>

   
As per coding guidelines: `**/*.mdx`: Use shadcn registry URL format `https://animata.design/r/{category}/{name}.json` in docs/changelog — never bare `npx shadcn add component-name`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @content/docs/section/animated-pricing-cards.mdx around lines 16 - 22, The
Installation section currently only documents the generator command yarn animata:new; update that section to also show the direct registry install URL
using the shadcn registry format
https://animata.design/r/{category}/{name}.json and include the concrete URL
for this component (category "section", name "animated-pricing-cards") so
readers can install directly without the generator; modify content in
animated-pricing-cards.mdx to include one sentence after the generator
instructions that provides the registry URL and an example using the component's
category/name format.


</details>

---

`106-106`: _⚠️ Potential issue_ | _🟡 Minor_

**Motion handling docs are inaccurate for the current implementation.**

This line says reduced motion is handled via `useReducedMotion()` hook, but the component currently uses `motion-safe` / `motion-reduce` classes.

<details>
<summary>Suggested doc patch</summary>

```diff
-- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook
+- **Motion handling**: Animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` utility classes
#!/bin/bash
set -e
echo "Doc line check:"
sed -n '99,110p' content/docs/section/animated-pricing-cards.mdx

echo
echo "Implementation check:"
rg -n 'useReducedMotion|motion-safe|motion-reduce' animata/section/animated-pricing-cards.tsx

Expected: docs currently mention useReducedMotion, while implementation matches motion-safe / motion-reduce.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/docs/section/animated-pricing-cards.mdx` at line 106, Update the
documentation sentence that currently claims reduced-motion is handled via
useReducedMotion() to reflect the actual implementation: mention that the
component uses Tailwind's motion-safe / motion-reduce utility classes
(motion-safe and motion-reduce) to respect prefers-reduced-motion. Replace the
reference to useReducedMotion() in the animated-pricing-cards docs and, if
helpful, add a brief note that these Tailwind classes wrap the animation CSS
rather than a React hook.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 16-22: The Installation section currently only documents the
generator command `yarn animata:new`; update that section to also show the
direct registry install URL using the shadcn registry format
`https://animata.design/r/{category}/{name}.json` and include the concrete URL
for this component (category "section", name "animated-pricing-cards") so
readers can install directly without the generator; modify content in
animated-pricing-cards.mdx to include one sentence after the generator
instructions that provides the registry URL and an example using the component's
category/name format.
- Line 106: Update the documentation sentence that currently claims
reduced-motion is handled via useReducedMotion() to reflect the actual
implementation: mention that the component uses Tailwind's motion-safe /
motion-reduce utility classes (motion-safe and motion-reduce) to respect
prefers-reduced-motion. Replace the reference to useReducedMotion() in the
animated-pricing-cards docs and, if helpful, add a brief note that these
Tailwind classes wrap the animation CSS rather than a React hook.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a63fa4c-6c86-404d-a771-3e12ae2e3e10

📥 Commits

Reviewing files that changed from the base of the PR and between edbe9a7 and 5b135d2.

📒 Files selected for processing (1)
  • content/docs/section/animated-pricing-cards.mdx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants