Skip to content

Conversation

@deepansh946
Copy link

@deepansh946 deepansh946 commented Nov 12, 2025

Closes #5785

📝 Description

Adds support for direct slot overrides in extendVariants function. Users can now override base component slots globally using the slots option, which applies styles to specific slots regardless of variants. Variant-based slot overrides continue to work and merge with direct slots.

⛳️ Current behavior (updates)

Previously, the slots option in extendVariants was typed but not implemented. Attempting to override base component slots (e.g., label slot in Input component) had no effect, even when using !important specifiers.

🚀 New behavior

  • Direct slot overrides via slots option now work correctly
  • Direct slots merge with variant-based slots (both are applied)
  • Direct slots override inferred slots (empty strings from variants) in the slots object
  • Added comprehensive tests covering direct slots, merging behavior, and override precedence

Example usage:

const MyInput = extendVariants(Input, {
  slots: {
    label: "!font-medium",
  },
});

💣 Is this a breaking change (Yes/No):

No

📝 Additional Information

  • Implementation merges direct slots with inferred slots from variants
  • Direct slots are passed to tv() function as base slots, which then merge with variant-based slots
  • Documentation updated to reflect the new slots option capability
  • TypeScript types already included slots option, so no type changes needed

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ability to override base component slots globally via the slots option. Direct slots now merge seamlessly with variant-based slots for flexible customization.
  • Documentation

    • Updated customization guide with new section on overriding base component slots, including practical code examples and usage notes.

@changeset-bot
Copy link

changeset-bot bot commented Nov 12, 2025

⚠️ No Changeset found

Latest commit: 9b34bc2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Nov 12, 2025

@deepansh946 is attempting to deploy a commit to the HeroUI Inc Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

Adds slot override capability to extendVariants by implementing a merge mechanism between directly provided slots and inferred slots from variants. Includes documentation updates, test coverage, and core implementation changes to support the feature.

Changes

Cohort / File(s) Summary
Documentation
apps/docs/content/docs/customization/custom-variants.mdx
Added "Overriding base component slots" section with code example; updated descriptions to include slots as override capability; introduced slots?: Record<string, ClassValue> property in ExtendVariantsOptions type.
Tests
packages/core/system-rsc/__tests__/extend-variants.test.tsx
Added three test cases validating direct slot overrides, merging of direct slots with variant-based slots, and precedence behavior when both affect the same slot.
Core Implementation
packages/core/system-rsc/src/extend-variants.js
Implemented slot merging logic: extracts direct slots from styles.slots, computes inferred slots from variants, and merges both when direct slots are provided.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant extendVariants
    participant getSlots
    participant Merge

    User->>extendVariants: Provide styles with directSlots + variants
    extendVariants->>extendVariants: Extract directSlots from styles.slots
    extendVariants->>getSlots: Process variants
    getSlots-->>extendVariants: Return inferredSlots
    extendVariants->>Merge: Merge directSlots + inferredSlots
    Merge-->>extendVariants: Return merged slots
    extendVariants-->>User: Return component with merged slots
    
    Note over extendVariants,Merge: Direct slots take precedence<br/>but merge with inferred slots
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Core logic: Verify the slot merging implementation in extend-variants.js correctly prioritizes direct slots while preserving inferred variants
  • Test coverage: Ensure all three new test cases properly validate merging semantics and edge cases
  • Type safety: Confirm the new slots property in ExtendVariantsOptions aligns with the implementation and is properly exported

Suggested reviewers

  • jrgarciadev
  • wingkwong

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(slots): extendVariants fn to support slots' clearly and specifically describes the main change: implementing slots support in the extendVariants function.
Description check ✅ Passed The PR description includes all required template sections: issue reference (#5785), clear description, current behavior, new behavior, breaking change status, and additional implementation details.
Linked Issues check ✅ Passed All objectives from issue #5785 are met: slots option is now implemented, direct overrides work globally, variant-based slots merge correctly, and the reproducible bug scenario is fixed.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing slots support: core implementation in extend-variants.js, tests for the feature, and documentation updates. No unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0344123 and 9b34bc2.

📒 Files selected for processing (3)
  • apps/docs/content/docs/customization/custom-variants.mdx (3 hunks)
  • packages/core/system-rsc/__tests__/extend-variants.test.tsx (1 hunks)
  • packages/core/system-rsc/src/extend-variants.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/core/system-rsc/__tests__/extend-variants.test.tsx (2)
packages/core/system-rsc/src/extend-variants.js (1)
  • extendVariants (104-153)
packages/core/system-rsc/test-utils/slots-component.tsx (1)
  • Card (171-200)
🔇 Additional comments (6)
packages/core/system-rsc/src/extend-variants.js (1)

105-109: LGTM! Clean implementation of slot merging.

The implementation correctly:

  1. Extracts direct slots from the styles parameter
  2. Infers slot names from variants using getSlots() (which returns slot names initialized to empty strings)
  3. Merges them so direct slots provide base styles while preserving all variant-referenced slots
  4. Passes the merged slots to tv() where variant-based slot styles are applied on top

This approach ensures direct slots act as base styles that apply globally, while variant-based slots can still add or merge additional styles through tailwind-merge.

packages/core/system-rsc/__tests__/extend-variants.test.tsx (3)

257-273: Good test coverage for direct slots.

This test validates that direct slots can override base component slot styles. The use of !important utilities (!font-bold, !text-lg, !bg-red-500) effectively ensures these styles take CSS precedence over the base Card component's default styles.


275-299: LGTM! Validates merging of non-conflicting slots.

This test correctly verifies that direct slots (header) and variant-based slots (base) work together when targeting different slots. Both styles are applied as expected.


301-326: Test correctly validates merge behavior.

The test verifies that when both direct slots and variant slots target the same slot (base), the styles merge rather than replace. Both !bg-blue-500 and shadow-xl are present because they're different utility types that coexist through tailwind-merge.

The test name says "override" but the behavior is actually "merge" - which is correct for how tv() combines base slots with variant slots. The !important on !bg-blue-500 ensures CSS specificity, not merge order precedence. This might be slightly confusing but accurately tests the intended behavior.

apps/docs/content/docs/customization/custom-variants.mdx (2)

8-8: Excellent documentation for the new feature.

The documentation clearly explains:

  • The new slots option for global slot overrides
  • That variant-based slot overrides still work and merge with direct slots
  • Practical example with !font-medium demonstrating the use case from the linked issue

The explanation accurately reflects the implementation behavior where direct slots become base styles that apply regardless of variants, and variant-based slots merge on top.

Also applies to: 218-234


258-258: Type definition correctly documented.

The slots option is properly added to the ExtendVariantsOptions type definition in the documentation, making it discoverable for users.


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

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 12, 2025

Open in StackBlitz

@heroui/accordion

npm i https://pkg.pr.new/@heroui/accordion@5895

@heroui/alert

npm i https://pkg.pr.new/@heroui/alert@5895

@heroui/autocomplete

npm i https://pkg.pr.new/@heroui/autocomplete@5895

@heroui/avatar

npm i https://pkg.pr.new/@heroui/avatar@5895

@heroui/badge

npm i https://pkg.pr.new/@heroui/badge@5895

@heroui/breadcrumbs

npm i https://pkg.pr.new/@heroui/breadcrumbs@5895

@heroui/button

npm i https://pkg.pr.new/@heroui/button@5895

@heroui/calendar

npm i https://pkg.pr.new/@heroui/calendar@5895

@heroui/card

npm i https://pkg.pr.new/@heroui/card@5895

@heroui/checkbox

npm i https://pkg.pr.new/@heroui/checkbox@5895

@heroui/chip

npm i https://pkg.pr.new/@heroui/chip@5895

@heroui/code

npm i https://pkg.pr.new/@heroui/code@5895

@heroui/date-input

npm i https://pkg.pr.new/@heroui/date-input@5895

@heroui/date-picker

npm i https://pkg.pr.new/@heroui/date-picker@5895

@heroui/divider

npm i https://pkg.pr.new/@heroui/divider@5895

@heroui/drawer

npm i https://pkg.pr.new/@heroui/drawer@5895

@heroui/dropdown

npm i https://pkg.pr.new/@heroui/dropdown@5895

@heroui/form

npm i https://pkg.pr.new/@heroui/form@5895

@heroui/image

npm i https://pkg.pr.new/@heroui/image@5895

@heroui/input

npm i https://pkg.pr.new/@heroui/input@5895

@heroui/input-otp

npm i https://pkg.pr.new/@heroui/input-otp@5895

@heroui/kbd

npm i https://pkg.pr.new/@heroui/kbd@5895

@heroui/link

npm i https://pkg.pr.new/@heroui/link@5895

@heroui/listbox

npm i https://pkg.pr.new/@heroui/listbox@5895

@heroui/menu

npm i https://pkg.pr.new/@heroui/menu@5895

@heroui/modal

npm i https://pkg.pr.new/@heroui/modal@5895

@heroui/navbar

npm i https://pkg.pr.new/@heroui/navbar@5895

@heroui/number-input

npm i https://pkg.pr.new/@heroui/number-input@5895

@heroui/pagination

npm i https://pkg.pr.new/@heroui/pagination@5895

@heroui/popover

npm i https://pkg.pr.new/@heroui/popover@5895

@heroui/progress

npm i https://pkg.pr.new/@heroui/progress@5895

@heroui/radio

npm i https://pkg.pr.new/@heroui/radio@5895

@heroui/ripple

npm i https://pkg.pr.new/@heroui/ripple@5895

@heroui/scroll-shadow

npm i https://pkg.pr.new/@heroui/scroll-shadow@5895

@heroui/select

npm i https://pkg.pr.new/@heroui/select@5895

@heroui/skeleton

npm i https://pkg.pr.new/@heroui/skeleton@5895

@heroui/slider

npm i https://pkg.pr.new/@heroui/slider@5895

@heroui/snippet

npm i https://pkg.pr.new/@heroui/snippet@5895

@heroui/spacer

npm i https://pkg.pr.new/@heroui/spacer@5895

@heroui/spinner

npm i https://pkg.pr.new/@heroui/spinner@5895

@heroui/switch

npm i https://pkg.pr.new/@heroui/switch@5895

@heroui/table

npm i https://pkg.pr.new/@heroui/table@5895

@heroui/tabs

npm i https://pkg.pr.new/@heroui/tabs@5895

@heroui/toast

npm i https://pkg.pr.new/@heroui/toast@5895

@heroui/tooltip

npm i https://pkg.pr.new/@heroui/tooltip@5895

@heroui/user

npm i https://pkg.pr.new/@heroui/user@5895

@heroui/react

npm i https://pkg.pr.new/@heroui/react@5895

@heroui/system

npm i https://pkg.pr.new/@heroui/system@5895

@heroui/system-rsc

npm i https://pkg.pr.new/@heroui/system-rsc@5895

@heroui/theme

npm i https://pkg.pr.new/@heroui/theme@5895

@heroui/use-aria-accordion

npm i https://pkg.pr.new/@heroui/use-aria-accordion@5895

@heroui/use-aria-accordion-item

npm i https://pkg.pr.new/@heroui/use-aria-accordion-item@5895

@heroui/use-aria-button

npm i https://pkg.pr.new/@heroui/use-aria-button@5895

@heroui/use-aria-link

npm i https://pkg.pr.new/@heroui/use-aria-link@5895

@heroui/use-aria-modal-overlay

npm i https://pkg.pr.new/@heroui/use-aria-modal-overlay@5895

@heroui/use-aria-multiselect

npm i https://pkg.pr.new/@heroui/use-aria-multiselect@5895

@heroui/use-aria-overlay

npm i https://pkg.pr.new/@heroui/use-aria-overlay@5895

@heroui/use-callback-ref

npm i https://pkg.pr.new/@heroui/use-callback-ref@5895

@heroui/use-clipboard

npm i https://pkg.pr.new/@heroui/use-clipboard@5895

@heroui/use-data-scroll-overflow

npm i https://pkg.pr.new/@heroui/use-data-scroll-overflow@5895

@heroui/use-disclosure

npm i https://pkg.pr.new/@heroui/use-disclosure@5895

@heroui/use-draggable

npm i https://pkg.pr.new/@heroui/use-draggable@5895

@heroui/use-form-reset

npm i https://pkg.pr.new/@heroui/use-form-reset@5895

@heroui/use-image

npm i https://pkg.pr.new/@heroui/use-image@5895

@heroui/use-infinite-scroll

npm i https://pkg.pr.new/@heroui/use-infinite-scroll@5895

@heroui/use-intersection-observer

npm i https://pkg.pr.new/@heroui/use-intersection-observer@5895

@heroui/use-is-mobile

npm i https://pkg.pr.new/@heroui/use-is-mobile@5895

@heroui/use-is-mounted

npm i https://pkg.pr.new/@heroui/use-is-mounted@5895

@heroui/use-measure

npm i https://pkg.pr.new/@heroui/use-measure@5895

@heroui/use-pagination

npm i https://pkg.pr.new/@heroui/use-pagination@5895

@heroui/use-real-shape

npm i https://pkg.pr.new/@heroui/use-real-shape@5895

@heroui/use-ref-state

npm i https://pkg.pr.new/@heroui/use-ref-state@5895

@heroui/use-resize

npm i https://pkg.pr.new/@heroui/use-resize@5895

@heroui/use-safe-layout-effect

npm i https://pkg.pr.new/@heroui/use-safe-layout-effect@5895

@heroui/use-scroll-position

npm i https://pkg.pr.new/@heroui/use-scroll-position@5895

@heroui/use-ssr

npm i https://pkg.pr.new/@heroui/use-ssr@5895

@heroui/use-theme

npm i https://pkg.pr.new/@heroui/use-theme@5895

@heroui/use-update-effect

npm i https://pkg.pr.new/@heroui/use-update-effect@5895

@heroui/use-viewport-size

npm i https://pkg.pr.new/@heroui/use-viewport-size@5895

@heroui/aria-utils

npm i https://pkg.pr.new/@heroui/aria-utils@5895

@heroui/dom-animation

npm i https://pkg.pr.new/@heroui/dom-animation@5895

@heroui/framer-utils

npm i https://pkg.pr.new/@heroui/framer-utils@5895

@heroui/react-rsc-utils

npm i https://pkg.pr.new/@heroui/react-rsc-utils@5895

@heroui/react-utils

npm i https://pkg.pr.new/@heroui/react-utils@5895

@heroui/shared-icons

npm i https://pkg.pr.new/@heroui/shared-icons@5895

@heroui/shared-utils

npm i https://pkg.pr.new/@heroui/shared-utils@5895

@heroui/stories-utils

npm i https://pkg.pr.new/@heroui/stories-utils@5895

@heroui/test-utils

npm i https://pkg.pr.new/@heroui/test-utils@5895

commit: 9b34bc2

@deepansh946
Copy link
Author

@wingkwong Please review the PR, I have made the required changes, added tests & also updated the documentation.

@wingkwong wingkwong added this to the v2.8.6 milestone Nov 15, 2025
@wingkwong wingkwong self-assigned this Nov 15, 2025
@vercel
Copy link

vercel bot commented Nov 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
heroui Ready Ready Preview Comment Nov 15, 2025 2:03pm
heroui-sb Ready Ready Preview Comment Nov 15, 2025 2:03pm

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.

[BUG] - slots option in extendVariants does not override base component styles

2 participants