Skip to content

fix(link): link overriding role#5999

Merged
wingkwong merged 2 commits into
heroui-inc:canaryfrom
hasegawa-101:fix/issue-5993
Dec 18, 2025
Merged

fix(link): link overriding role#5999
wingkwong merged 2 commits into
heroui-inc:canaryfrom
hasegawa-101:fix/issue-5993

Conversation

@hasegawa-101
Copy link
Copy Markdown

@hasegawa-101 hasegawa-101 commented Dec 17, 2025

Closes #5993

📝 Description

Fixed an issue where the role attribute on the Link component could not be overridden by the user (e.g., role="button"). This PR updates the mergeProps order to prioritize user-defined props while strictly preserving the correctly resolved href from react-aria to maintain router compatibility.

⛳️ Current behavior (updates)

The Link component strictly prioritizes system default props over user-provided props. As a result, passing role="button" is ignored, and the component always renders with role="link", preventing users from creating button-like links purely via props.

🚀 New behavior

  • User Priority: Updated mergeProps order to prioritize otherProps (user input).
  • Href Safety: Explicitly restores the system-resolved href from linkProps to prevent it from being overwritten by raw props, ensuring correct routing paths (e.g., handling basePath).

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

No

📝 Additional Information

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 17, 2025

@hasegawa-101 is attempting to deploy a commit to the HeroUI Inc Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Dec 17, 2025

🦋 Changeset detected

Latest commit: 878a6be

The changes in this PR will be included in the next version bump.

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

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 17, 2025

Walkthrough

This PR fixes a bug where the Link component incorrectly overrode the role attribute when rendered as a button. Changes include a changeset entry, a new test case verifying button rendering with role preservation, and a modification to the use-link hook to correct prop merging order.

Changes

Cohort / File(s) Summary
Changeset entry
.changeset/real-turkeys-roll.md
Documents patch release for @heroui/link addressing role attribute override issue
Test coverage
packages/components/link/__tests__/link.test.tsx
Adds test case validating Link component renders as button with correct role, type, and without href attribute when as="button"
Link hook logic
packages/components/link/src/use-link.ts
Adjusts prop merging order in getLinkProps return to ensure href from linkProps is preserved and not overridden by spread props

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Attention area: The prop merging order change in use-link.ts — verify the new merge sequence correctly prioritizes href while allowing custom role attributes to pass through without being overridden.

Possibly related PRs

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 clearly and concisely describes the main fix: resolving the Link component's issue with overriding the role property.
Linked Issues check ✅ Passed The code changes directly address the bug in issue #5993: preserving the role prop when the Link is rendered as another element (e.g., as="button").
Out of Scope Changes check ✅ Passed All changes (test, use-link.ts, changeset) are focused on fixing the role prop override issue; no unrelated modifications detected.
Description check ✅ Passed The PR description includes all required sections from the template with substantive content addressing the issue, current behavior, new behavior, and breaking change status.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@hasegawa-101 hasegawa-101 changed the title fix(link): allow overriding role fix(link): link overriding role Dec 17, 2025
@hasegawa-101 hasegawa-101 marked this pull request as ready for review December 17, 2025 10:37
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Dec 17, 2025

Open in StackBlitz

@heroui/accordion

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

@heroui/alert

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

@heroui/autocomplete

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

@heroui/avatar

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

@heroui/badge

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

@heroui/breadcrumbs

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

@heroui/button

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

@heroui/calendar

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

@heroui/card

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

@heroui/checkbox

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

@heroui/chip

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

@heroui/code

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

@heroui/date-input

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

@heroui/date-picker

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

@heroui/divider

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

@heroui/drawer

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

@heroui/dropdown

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

@heroui/form

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

@heroui/image

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

@heroui/input

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

@heroui/input-otp

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

@heroui/kbd

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

@heroui/link

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

@heroui/listbox

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

@heroui/menu

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

@heroui/modal

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

@heroui/navbar

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

@heroui/number-input

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

@heroui/pagination

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

@heroui/popover

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

@heroui/progress

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

@heroui/radio

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

@heroui/ripple

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

@heroui/scroll-shadow

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

@heroui/select

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

@heroui/skeleton

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

@heroui/slider

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

@heroui/snippet

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

@heroui/spacer

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

@heroui/spinner

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

@heroui/switch

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

@heroui/table

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

@heroui/tabs

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

@heroui/toast

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

@heroui/tooltip

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

@heroui/user

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

@heroui/react

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

@heroui/system

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

@heroui/system-rsc

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

@heroui/theme

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

@heroui/use-aria-accordion

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

@heroui/use-aria-accordion-item

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

@heroui/use-aria-button

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

@heroui/use-aria-link

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

@heroui/use-aria-modal-overlay

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

@heroui/use-aria-multiselect

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

@heroui/use-aria-overlay

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

@heroui/use-callback-ref

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

@heroui/use-clipboard

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

@heroui/use-data-scroll-overflow

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

@heroui/use-disclosure

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

@heroui/use-draggable

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

@heroui/use-form-reset

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

@heroui/use-image

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

@heroui/use-infinite-scroll

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

@heroui/use-intersection-observer

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

@heroui/use-is-mobile

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

@heroui/use-is-mounted

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

@heroui/use-measure

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

@heroui/use-pagination

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

@heroui/use-real-shape

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

@heroui/use-ref-state

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

@heroui/use-resize

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

@heroui/use-safe-layout-effect

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

@heroui/use-scroll-position

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

@heroui/use-ssr

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

@heroui/use-theme

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

@heroui/use-update-effect

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

@heroui/use-viewport-size

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

@heroui/aria-utils

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

@heroui/dom-animation

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

@heroui/framer-utils

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

@heroui/react-rsc-utils

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

@heroui/react-utils

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

@heroui/shared-icons

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

@heroui/shared-utils

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

@heroui/stories-utils

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

@heroui/test-utils

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

commit: 878a6be

Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
packages/components/link/__tests__/link.test.tsx (1)

102-114: Test validates the fix but could be more explicit.

The test correctly verifies that as="button" with explicit role="button" renders as a button element. Using getByRole("button") implicitly validates that role="button" is present, which is good.

However, consider these improvements:

  1. Explicit role assertion: Add expect(button).toHaveAttribute("role", "button") to make the role validation explicit rather than implicit.

  2. Regression test: Add a test case for the exact scenario from issue #5993: as="button" href="#" role="button" to ensure the explicit role is preserved even when href is present.

Example addition:

+  it("should respect explicit role even when href is present", () => {
+    const {getByRole} = render(
+      <Link as="button" href="#" role="button" type="button">
+        Button Link
+      </Link>,
+    );
+
+    const button = getByRole("button");
+
+    expect(button.tagName).toBe("BUTTON");
+    expect(button).toHaveAttribute("role", "button");
+    expect(button).toHaveAttribute("type", "button");
+  });
📜 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 acc74d1 and 878a6be.

📒 Files selected for processing (3)
  • .changeset/real-turkeys-roll.md (1 hunks)
  • packages/components/link/__tests__/link.test.tsx (1 hunks)
  • packages/components/link/src/use-link.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: TypeScript
  • GitHub Check: Continuous Release
  • GitHub Check: Build
🔇 Additional comments (3)
packages/components/link/src/use-link.ts (2)

3-3: LGTM: Import addition supports type cast.

The AnchorHTMLAttributes import is necessary for the type cast on line 114.


113-115: Verify the prop merging order and type cast.

The reordering of mergeProps arguments (placing otherProps after linkProps) correctly allows user-provided props to override computed props. Analysis confirms:

  1. mergeProps behavior verified: For all other props, the last prop object overrides all previous ones. The explicit href override placement as the last argument ensures it always comes from linkProps.

  2. href handling on non-anchor elements is safe: The code passes elementType: \${as}`touseAriaLink(line 82). React Aria'suseLinkreturns element-type-aware props—for button elements, it doesn't includehrefinlinkProps. Therefore, (linkProps as AnchorHTMLAttributes).hrefisundefined` for buttons, preventing invalid href attributes from being added.

  3. Type cast concern noted: The cast indicates a potential typing mismatch with useAriaLink's return type, but this doesn't cause runtime issues. The test suite validates that button elements correctly exclude href attributes.

.changeset/real-turkeys-roll.md (1)

1-5: LGTM: Changeset correctly documents the fix.

The changeset properly documents this as a patch release for @heroui/link with a clear reference to issue #5993.

@wingkwong wingkwong added this to the v2.8.7 milestone Dec 17, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 17, 2025

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

Project Deployment Review Updated (UTC)
heroui Ready Ready Preview, Comment Dec 17, 2025 1:54pm
heroui-sb Ready Ready Preview, Comment Dec 17, 2025 1:54pm

@wingkwong wingkwong merged commit 090b151 into heroui-inc:canary Dec 18, 2025
10 checks passed
jrgarciadev added a commit that referenced this pull request Dec 25, 2025
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

* ci(changesets): version packages (#5991)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
wingkwong added a commit that referenced this pull request Jan 29, 2026
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

* ci(changesets): version packages (#5991)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)

* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>

* fix(docs): broken links in Form page (#6077)

* fix(pagination): improve layout for large page counts (#6034)

* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

* chore(changeset): revise message and add issue numbers

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(date-picker): open date-picker when clicking border (#6084)

* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(accordion): click behaviour for dynamically generated accordion items (#6133)

* fix(accordion): add collection state

* chore: add changeset

* fix: update change set

* refactor(theme): remove flat dependency (#6157)

* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset

* fix(listbox): prevent option focus from start/end content slots (#6060)

* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(system-rsc): extendVariants & compound variants types (#5847)

* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* chore(docs): update meta (#6168)

* ci(changesets): version packages (#6059)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: brianatdetections <brian@detections.ai>
Co-authored-by: Brian Meek <brian@current.space>
Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com>
Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com>
Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com>
Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com>
Co-authored-by: doki- <1335902682@qq.com>
jrgarciadev added a commit that referenced this pull request Feb 10, 2026
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

* ci(changesets): version packages (#5991)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)

* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>

* fix(docs): broken links in Form page (#6077)

* fix(pagination): improve layout for large page counts (#6034)

* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

* chore(changeset): revise message and add issue numbers

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(date-picker): open date-picker when clicking border (#6084)

* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(accordion): click behaviour for dynamically generated accordion items (#6133)

* fix(accordion): add collection state

* chore: add changeset

* fix: update change set

* refactor(theme): remove flat dependency (#6157)

* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset

* fix(listbox): prevent option focus from start/end content slots (#6060)

* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(system-rsc): extendVariants & compound variants types (#5847)

* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* chore(docs): update meta (#6168)

* ci(changesets): version packages (#6059)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: brianatdetections <brian@detections.ai>
Co-authored-by: Brian Meek <brian@current.space>
Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com>
Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com>
Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com>
Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com>
Co-authored-by: doki- <1335902682@qq.com>
jrgarciadev added a commit that referenced this pull request Feb 18, 2026
* fix(theme): hide password reveal button (#5990)

* fix(link): link overriding role (#5999)

* fix(link): allow overriding role

* chore(link): changeset

* chore(deps): upgrade react-aria (v1.14.0) (#5996)

* chore(deps): upgrade react-aria (v1.14.0)

* refactor(react): group client components

* fix(dropdown): keyDown test cases

* chore(react): rollback

* fix(theme): default transition-duration (#6011)

* fix(theme): default transitionDuration

* chore(deps): bump @heroui/theme peer dep

* ci(changesets): version packages (#5991)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(use-image): resolve race condition with cached images on Firefox/Safari (#6041)

* fix(use-image): resolve race condition with cached images on Firefox/Safari

The bug occurred because event handlers (onload/onerror) were attached
AFTER setting the image src. For cached images, browsers fire onload
synchronously when src is set, causing the event to be missed and
images to remain stuck at opacity-0.

Changes:
- Attach handlers BEFORE setting src to catch synchronous callbacks
- Check both naturalWidth AND naturalHeight (per CodeRabbit review on #4523)
- Handle synchronous error callbacks for failed cached images
- Add comprehensive test coverage (15 tests) including:
  - Synchronous cached image success (Firefox/Safari race condition)
  - Synchronous cached image error
  - Dynamic src changes
  - All props (crossOrigin, srcSet, sizes, loading)
  - Callback invocation verification

Reproduction and investigation performed using Claude Opus 4.5.

Fixes #4534, #2259

* fix(use-image): add ignoreFallback to useCallback dependencies

Address CodeRabbit review feedback: the `ignoreFallback` prop was used
inside the `load` callback (line 104) but was missing from the dependency
array, creating a stale closure bug.

Without this fix, if `ignoreFallback` changes from `true` to `false`
dynamically, the `load` callback would retain the stale `true` value,
preventing the image from ever loading.

Changes:
- Add `ignoreFallback` to useCallback dependency array
- Add tests for dynamic `ignoreFallback` changes (both directions)
- Update changeset to document this fix

Verification performed using Claude Opus 4.5.

---------

Co-authored-by: Brian Meek <brian@current.space>

* fix(docs): broken links in Form page (#6077)

* fix(pagination): improve layout for large page counts (#6034)

* fix(pagination): improve layout for large page counts/style of paagination compnents

* fix(pagination): refine item sizing to balance small and large page numbers

* ci(changesets): add pagination sizing changeset

* fix(pagination): ensure cursor fully covers button without changing radius

* chore(changeset): revise message and add issue numbers

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(date-picker): open date-picker when clicking border (#6084)

* fix(date-picker): add pointer interaction to open date picker on wrapper click

* chore: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(accordion): click behaviour for dynamically generated accordion items (#6133)

* fix(accordion): add collection state

* chore: add changeset

* fix: update change set

* refactor(theme): remove flat dependency (#6157)

* chore(deps): remove flat library

* refactor(theme): replace flatten from flat

* chore: add changeset

* fix(listbox): prevent option focus from start/end content slots (#6060)

* fix(listbox): prevent option focus from start/end content slots

* test: add test code about when clicking
non-interactive slot content, and prevented focus leakage from interactive
start/end content such as buttons.

* docs: add changeset

* chore(changeset): add issue number

---------

Co-authored-by: WK <wingkwong.code@gmail.com>

* fix(system-rsc): extendVariants & compound variants types (#5847)

* fix(extendVariants): return component type error

* fix(CompoundVariants): correct type inference for extended/compound variants and composition

* test: cover compound/extend inference; enforce CP required props

* fix(types): correct CompoundVariants class value inference

Replaces the conditional ClassProp logic with a simpler,
consistent form to fix incorrect slot value inference.

Before:
  ClassProp<S extends undefined ? ClassValue : ClassValue | SlotsClassValue<S>>

After:
  ClassProp<ClassValue | GetSuggestedValues<S>>

This ensures GetSuggestedValues<S> is used for slot-aware variants
and avoids duplicated conditional branches for undefined slots.

* fix(system-rsc): correct slot detection in getSlots()

* fix(types): make ExtendVariants props optional and guard V[key] with NonNullable

Simplifies the return type of ExtendVariants to ensure no required props
are enforced at the HOC level. This aligns with the intended API contract
where extended components expose all props as optional.

- All keys (CP ∪ V) are optional
- Preserve CP type hints and booleanized V values
- Added NonNullable<V[key]> guard to prevent undefined indexing

* test(extendVariants): add compoundVariants integration test

* fix(system-rsc): getSlots() brief JSDoc comment added

* test(extendVariants):  new styles - extended & fixed styles - original tests for slots component

* test(extendVariants): fixed slot component variant styles extended test

* fix(types): avoid leaking React internals by removing PropsWithoutRef

Replace PropsWithoutRef with explicit Exclude<'ref'> in mapped keys and
intersect with RefAttributes<InferRef<C>>. This prevents @types/react’s
internal UNDEFINED_VOID_ONLY from leaking into the public .d.ts and fixes
declaration emit for components like extended Autocomplete.

* chore(changeset): add patch for extendVariants and CompoundVariants type fix

* chore(system-rsc): add changeset for getSlots() slot detection fix

* refactor(types): unify slot value inference via GetSuggestedValues<S> for consistent variant typing

* fix(extendVariants): improved as-prop handling and exclude classNames from SuggestedVariants

* fix(system-rsc): add polymorphic 'as' prop support to extendVariants

* chore(system-rsc): add missing tests

---------

Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* chore(docs): update meta (#6168)

* ci(changesets): version packages (#6059)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* fix(system-rsc): extendVariants rendering behavior with as (#6215)

* fix(system-rsc): fix components rendering with 'as' prop

* fix(system-rsc): fix compoundVariants and slots inheritance in extendVariants

* fix(system-rsc): extendVariants test file cleaned

* chore(deps): bump RA dependencies (#6221)

* chore(deps): bump RA dependencies

* chore(date-picker): revise test cases

* fix(button): correct disableRipple prop precedence (#6199)

* ci(changesets): version packages (#6227)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Hayato Hasegawa <hase1225hayato@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: brianatdetections <brian@detections.ai>
Co-authored-by: Brian Meek <brian@current.space>
Co-authored-by: Dominik Hryshaiev <domhryshaiev@gmail.com>
Co-authored-by: creative-atish <149860680+atishkr25@users.noreply.github.com>
Co-authored-by: KyZy7 <29321162+KyZy7@users.noreply.github.com>
Co-authored-by: Deepansh Bhargava <deepansh940@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: Bohdan Kulinchenko <35272606+ITBoomBKStudio@users.noreply.github.com>
Co-authored-by: doki- <1335902682@qq.com>
Co-authored-by: Chris Nowak <krzysztofmareknowak@gmail.com>
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] - Can't set the aria role of a Link

2 participants