Skip to content

fix(chip,filter-chip): forward HTML attributes onto root element#769

Merged
rohilsurana merged 3 commits intomainfrom
fix/forward-html-attributes-chip-filterchip
May 4, 2026
Merged

fix(chip,filter-chip): forward HTML attributes onto root element#769
rohilsurana merged 3 commits intomainfrom
fix/forward-html-attributes-chip-filterchip

Conversation

@paanSinghCoder
Copy link
Copy Markdown
Contributor

@paanSinghCoder paanSinghCoder commented May 4, 2026

Summary

Closes the remaining gap from #674 — covers Chip (#605) and FilterChip (#616). The other components listed in #674 already extend the appropriate HTMLAttributes type and spread ...rest (verified against main at a7e6705).

  • Chip had a real runtime gap: it selectively picked onClick, role, data-state, disabled, ariaLabel and dropped everything else, so consumers couldn't pass style, id, data-*, aria-*, mouse events, etc.
  • FilterChip already spread ...props onto the root <Flex> at runtime, but FilterChipProps didn't extend any HTMLAttributes type — so TypeScript rejected those props at the call site.

Both now extend ComponentProps<'span'> / ComponentProps<'div'> and the Chip implementation spreads the rest props onto the root element. Existing prop API is preserved:

  • ariaLabel (legacy camelCase) still wins over the native aria-label
  • disabled still gates onClick and sets data-disabled
  • role still defaults to 'status' on Chip
  • data-state is still passed through (now via the spread instead of an explicit prop)

Components NOT changed (already compliant)

Component Status
Indicator (#622) already extends ComponentProps<'div'> and spreads
Image (#621) already extends ImgHTMLAttributes
IconButton (#620) already extends ComponentProps<'button'> and spreads
Headline (#619) uses Base UI useRender.ComponentProps<'h2'> + mergeProps
EmptyState (#615) already extends ComponentProps<typeof Flex>
CopyButton (#611) already extends IconButtonProps
Badge (#598) already extends ComponentProps<'span'>
Amount (#595) already extends ComponentProps<'span'>

If maintainers agree, #674 can be closed once this lands.

Test plan

  • pnpm test — full suite passes (1684 tests; +4 new covering arbitrary attribute forwarding on Chip and FilterChip)
  • pnpm build — typecheck clean
  • Existing ariaLabel, role, disabled, dismiss, and click behavior covered by existing Chip tests still pass
  • Verify in Storybook/docs that consumers can now pass style, data-*, id, onMouseEnter, etc.

🤖 Generated with Claude Code

Chip selectively picked props (`onClick`, `role`, `data-state`, etc.) and
did not spread the rest, so consumers couldn't pass `style`, `data-*`,
`aria-*`, `id`, mouse events, or any other native span attribute.
FilterChip already spread `...props` at runtime but its props interface
didn't extend any HTMLAttributes type, so the same attributes were
rejected by TypeScript.

Both components now extend `ComponentProps<'span' | 'div'>` and forward
all unspecified attributes to the root element. Existing prop API is
preserved: `ariaLabel` (legacy camelCase) still wins over the native
`aria-label`, the `disabled` gate on `onClick` still applies, and
`role` still defaults to `status` on Chip.

Closes part of #674.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

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

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment May 4, 2026 10:24am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

Warning

Rate limit exceeded

@paanSinghCoder has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 53 minutes and 53 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7e479bb-9c60-4f94-9631-2e4eabadee76

📥 Commits

Reviewing files that changed from the base of the PR and between e3fa200 and c14a51e.

📒 Files selected for processing (1)
  • docs/V1-migration.md
📝 Walkthrough

Walkthrough

The PR updates the Chip and FilterChip components to use native HTML attribute props instead of custom prop definitions. The Chip component now extends ComponentProps<'span'> and forwards remaining span props to its root element, with aria-label properly mapped from the standard 'aria-label' attribute. Similarly, FilterChip now extends ComponentProps<'div'>. Documentation examples and tests were updated to reflect the use of the standard aria-label attribute instead of the custom ariaLabel prop. Arbitrary HTML attributes and event handlers are now forwarded to the root element.

Possibly related issues

Suggested reviewers

  • rohanchkrabrty
  • rsbh
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding HTML attribute forwarding to the root elements of Chip and FilterChip components.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining what was fixed, why it was needed, and how the changes preserve backward compatibility.
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.


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: 0/1 reviews remaining, refill in 53 minutes and 53 seconds.

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

@paanSinghCoder
Copy link
Copy Markdown
Contributor Author

Closing for now — keeping changes local for further testing.

Comment thread packages/raystack/components/chip/chip.tsx Outdated
@paanSinghCoder paanSinghCoder requested a review from rsbh May 4, 2026 10:18
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/raystack/components/filter-chip/filter-chip.tsx (1)

160-168: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

{...props} placed after accessibility-critical attrs — user props silently win.

Because role and aria-label are not destructured out of FilterChipProps, they remain in ...props. In JSX, later props override earlier ones, so a consumer who passes role='region' or aria-label='custom' will silently clobber role='group' and the computed Filter by ${label} label. data-variant is similarly overridable.

Chip avoids this by spreading {...props} first and setting its controlled attributes after. FilterChip should follow the same pattern:

🛡️ Proposed fix — mirror the Chip spread order
   return (
     <Flex
       align='center'
       ref={ref}
-      className={chip({ variant, className })}
-      role='group'
-      aria-label={`Filter by ${label}`}
-      data-variant={variant}
       {...props}
+      className={chip({ variant, className })}
+      role='group'
+      aria-label={`Filter by ${label}`}
+      data-variant={variant}
     >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/filter-chip/filter-chip.tsx` around lines 160 -
168, The FilterChip component currently spreads {...props} after accessibility
attributes so consumer props can overwrite role, aria-label and data-variant;
update the JSX in the FilterChip (the Flex element in filter-chip.tsx) to spread
{...props} first and then set controlled attributes (role='group',
aria-label={`Filter by ${label}`}, data-variant={variant}), or alternatively
destructure role and aria-label out of FilterChipProps to prevent them being
included in ...props and ensure the component-controlled values (in the
FilterChip/Flex render) always override consumer-supplied values.
packages/raystack/components/chip/chip.tsx (1)

30-54: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Removing ariaLabel is a breaking change for existing consumers.

The previous Chip API accepted ariaLabel?: string as a custom prop. This PR replaces it entirely with the native 'aria-label' attribute without providing any backward-compatible alias or deprecation path. A consumer who today writes <Chip ariaLabel="..." /> will silently drop the label at runtime (TypeScript will also produce a type error once they upgrade to this version).

The playground and docs were updated in this PR, but external package consumers won't know to migrate.

A low-effort, backward-compatible fix is to keep ariaLabel as a deprecated alias that feeds the same internal variable:

🔄 Proposed backward-compatible fix
 type ChipProps = ComponentProps<'span'> &
   VariantProps<typeof chip> & {
     trailingIcon?: ReactNode;
     leadingIcon?: ReactNode;
     isDismissible?: boolean;
     children: ReactNode;
     onDismiss?: () => void;
     disabled?: boolean;
+    /** `@deprecated` Use the native `aria-label` attribute instead. */
+    ariaLabel?: string;
   };
 export const Chip = ({
   ...
-  'aria-label': ariaLabel,
+  'aria-label': ariaLabelNative,
+  ariaLabel: ariaLabelLegacy,
   ...props
 }: ChipProps) => {
+  const ariaLabel = ariaLabelNative ?? ariaLabelLegacy;

Alternatively, if this is intentionally a breaking change (semver-major), it should be called out clearly in the changelog/migration notes.

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

In `@packages/raystack/components/chip/chip.tsx` around lines 30 - 54, The PR
removed the legacy ariaLabel prop causing a breaking change; restore
backward-compatibility by adding ariaLabel?: string to ChipProps and accept
ariaLabel in the Chip parameter list alongside the native 'aria-label'
destructure, then compute a single value (e.g., const resolvedAriaLabel =
ariaLabel ?? ariaLabelNative) and pass that as the element's 'aria-label'
attribute; reference the ChipProps type, the Chip component function, the
existing 'aria-label' destructured identifier (currently named ariaLabel in the
code), and add a short deprecation comment on ariaLabel to indicate it will be
removed in a future major release.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/raystack/components/chip/__tests__/chip.test.tsx`:
- Around line 231-236: The test "accepts native aria-label attribute" is
redundant because it duplicates the assertion path of the existing "uses custom
aria-label when provided" test; remove the entire it block named "accepts native
aria-label attribute" from the chip.test.tsx file (the render(<Chip
aria-label='...'>...); + expect(...toHaveAttribute('aria-label', ...)) block)
and keep the distinct "uses custom aria-label when provided" and the override
test that checks precedence (both referenced in the same test suite).

---

Outside diff comments:
In `@packages/raystack/components/chip/chip.tsx`:
- Around line 30-54: The PR removed the legacy ariaLabel prop causing a breaking
change; restore backward-compatibility by adding ariaLabel?: string to ChipProps
and accept ariaLabel in the Chip parameter list alongside the native
'aria-label' destructure, then compute a single value (e.g., const
resolvedAriaLabel = ariaLabel ?? ariaLabelNative) and pass that as the element's
'aria-label' attribute; reference the ChipProps type, the Chip component
function, the existing 'aria-label' destructured identifier (currently named
ariaLabel in the code), and add a short deprecation comment on ariaLabel to
indicate it will be removed in a future major release.

In `@packages/raystack/components/filter-chip/filter-chip.tsx`:
- Around line 160-168: The FilterChip component currently spreads {...props}
after accessibility attributes so consumer props can overwrite role, aria-label
and data-variant; update the JSX in the FilterChip (the Flex element in
filter-chip.tsx) to spread {...props} first and then set controlled attributes
(role='group', aria-label={`Filter by ${label}`}, data-variant={variant}), or
alternatively destructure role and aria-label out of FilterChipProps to prevent
them being included in ...props and ensure the component-controlled values (in
the FilterChip/Flex render) always override consumer-supplied values.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71336f27-2570-475b-8003-d1b54be89d53

📥 Commits

Reviewing files that changed from the base of the PR and between 90f2754 and e3fa200.

📒 Files selected for processing (7)
  • apps/www/src/components/playground/chip-examples.tsx
  • apps/www/src/content/docs/components/chip/demo.ts
  • apps/www/src/content/docs/components/chip/props.ts
  • packages/raystack/components/chip/__tests__/chip.test.tsx
  • packages/raystack/components/chip/chip.tsx
  • packages/raystack/components/filter-chip/__tests__/filter-chip.test.tsx
  • packages/raystack/components/filter-chip/filter-chip.tsx

Comment on lines +231 to +236
it('accepts native aria-label attribute', () => {
render(<Chip aria-label='Native Label'>String Child</Chip>);

const chip = screen.getByRole('status');
expect(chip).toHaveAttribute('aria-label', 'Native Label');
});
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Redundant test — identical assertion path to the test at Line 217.

"accepts native aria-label attribute" (lines 231-236) and "uses custom aria-label when provided" (lines 217-222) both render <Chip aria-label='...' /> and assert toHaveAttribute('aria-label', ...). They exercise the exact same code path; the only variation is the label/children string.

The "override" test at lines 224-229 is distinct (string child + explicit aria-label — checks precedence) and should be kept.

🗑️ Proposed removal
-    it('accepts native aria-label attribute', () => {
-      render(<Chip aria-label='Native Label'>String Child</Chip>);
-
-      const chip = screen.getByRole('status');
-      expect(chip).toHaveAttribute('aria-label', 'Native Label');
-    });
📝 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
it('accepts native aria-label attribute', () => {
render(<Chip aria-label='Native Label'>String Child</Chip>);
const chip = screen.getByRole('status');
expect(chip).toHaveAttribute('aria-label', 'Native Label');
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/chip/__tests__/chip.test.tsx` around lines 231 -
236, The test "accepts native aria-label attribute" is redundant because it
duplicates the assertion path of the existing "uses custom aria-label when
provided" test; remove the entire it block named "accepts native aria-label
attribute" from the chip.test.tsx file (the render(<Chip aria-label='...'>...);
+ expect(...toHaveAttribute('aria-label', ...)) block) and keep the distinct
"uses custom aria-label when provided" and the override test that checks
precedence (both referenced in the same test suite).

@rohilsurana rohilsurana merged commit 3017349 into main May 4, 2026
5 checks passed
@rohilsurana rohilsurana deleted the fix/forward-html-attributes-chip-filterchip branch May 4, 2026 10:27
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