diff --git a/apps/www/src/components/playground/chip-examples.tsx b/apps/www/src/components/playground/chip-examples.tsx
index 6c29e5ef5..8446356e7 100644
--- a/apps/www/src/components/playground/chip-examples.tsx
+++ b/apps/www/src/components/playground/chip-examples.tsx
@@ -35,7 +35,7 @@ export function ChipExamples() {
alert('dismissed')}
- ariaLabel='Dismissible chip'
+ aria-label='Dismissible chip'
>
Dismissable Chip
@@ -44,7 +44,7 @@ export function ChipExamples() {
color='accent'
isDismissible
onDismiss={() => alert('dismissed')}
- ariaLabel='Dismissible chip'
+ aria-label='Dismissible chip'
>
Dismissable Chip
@@ -53,7 +53,7 @@ export function ChipExamples() {
color='accent'
isDismissible
onDismiss={() => alert('dismissed')}
- ariaLabel='Dismissible chip'
+ aria-label='Dismissible chip'
>
Dismissable Chip
diff --git a/apps/www/src/content/docs/components/chip/demo.ts b/apps/www/src/content/docs/components/chip/demo.ts
index 6591c9706..e15705ceb 100644
--- a/apps/www/src/content/docs/components/chip/demo.ts
+++ b/apps/www/src/content/docs/components/chip/demo.ts
@@ -73,9 +73,9 @@ export const dismissableDemo = {
type: 'code',
code: `
- alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip
- alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip
- alert('dismissed')} ariaLabel="Dismissible chip">Dismissable Chip
+ alert('dismissed')} aria-label="Dismissible chip">Dismissable Chip
+ alert('dismissed')} aria-label="Dismissible chip">Dismissable Chip
+ alert('dismissed')} aria-label="Dismissible chip">Dismissable Chip
`
};
diff --git a/apps/www/src/content/docs/components/chip/props.ts b/apps/www/src/content/docs/components/chip/props.ts
index 99396d0d7..9f270cd68 100644
--- a/apps/www/src/content/docs/components/chip/props.ts
+++ b/apps/www/src/content/docs/components/chip/props.ts
@@ -44,5 +44,5 @@ export interface ChipProps {
role?: string;
/** Custom accessibility label for the chip */
- ariaLabel?: string;
+ 'aria-label'?: string;
}
diff --git a/docs/V1-migration.md b/docs/V1-migration.md
index 40996ba86..903b1f31c 100644
--- a/docs/V1-migration.md
+++ b/docs/V1-migration.md
@@ -21,6 +21,7 @@ This guide covers all breaking changes when upgrading from the last stable Radix
- [Avatar](#avatar)
- [Breadcrumb](#breadcrumb)
- [Button](#button)
+ - [Chip](#chip)
- [Checkbox](#checkbox)
- [New: `Checkbox.Group`](#new-checkboxgroup)
- [New Features](#new-features)
@@ -418,6 +419,31 @@ Unchanged: `size`, `radius`, `variant`, `color`, `fallback`, `src`, `alt`, `clas
---
+### Chip
+
+**`ariaLabel` prop removed** -- use the standard `aria-label` HTML attribute:
+
+```tsx
+// Before
+
+ Tag
+
+
+// After
+
+ Tag
+
+```
+
+`Chip` now forwards all standard HTML attributes through `...props`, making the dedicated `ariaLabel` prop redundant. The auto-fallback to string children when no label is supplied is unchanged:
+
+```tsx
+// Still works — uses "Tag" as the accessibility label
+Tag
+```
+
+---
+
### Checkbox
1. **Indeterminate API changed** -- `checked="indeterminate"` replaced by separate `indeterminate` boolean:
diff --git a/packages/raystack/components/chip/__tests__/chip.test.tsx b/packages/raystack/components/chip/__tests__/chip.test.tsx
index a15348866..ad5b58385 100644
--- a/packages/raystack/components/chip/__tests__/chip.test.tsx
+++ b/packages/raystack/components/chip/__tests__/chip.test.tsx
@@ -214,18 +214,57 @@ describe('Chip', () => {
expect(chip).toHaveAttribute('aria-label', 'Test Label');
});
- it('uses custom ariaLabel when provided', () => {
- render(Test Chip);
+ it('uses custom aria-label when provided', () => {
+ render(Test Chip);
const chip = screen.getByRole('status');
expect(chip).toHaveAttribute('aria-label', 'Custom Label');
});
- it('custom ariaLabel overrides string children', () => {
- render(String Child);
+ it('custom aria-label overrides string children', () => {
+ render(String Child);
const chip = screen.getByRole('status');
expect(chip).toHaveAttribute('aria-label', 'Override Label');
});
+
+ it('accepts native aria-label attribute', () => {
+ render(String Child);
+
+ const chip = screen.getByRole('status');
+ expect(chip).toHaveAttribute('aria-label', 'Native Label');
+ });
+ });
+
+ describe('Forwarded HTML attributes', () => {
+ it('forwards arbitrary HTML attributes onto the root span', () => {
+ render(
+
+ Test Chip
+
+ );
+
+ const chip = screen.getByTestId('chip-root');
+ expect(chip).toHaveAttribute('id', 'my-chip');
+ expect(chip).toHaveAttribute('data-state', 'active');
+ expect(chip).toHaveAttribute('title', 'Tooltip');
+ });
+
+ it('forwards mouse events from the spread props', () => {
+ const onMouseEnter = vi.fn();
+ render(
+
+ Test Chip
+
+ );
+
+ fireEvent.mouseEnter(screen.getByTestId('chip-root'));
+ expect(onMouseEnter).toHaveBeenCalledTimes(1);
+ });
});
});
diff --git a/packages/raystack/components/chip/chip.tsx b/packages/raystack/components/chip/chip.tsx
index 424298a4f..ccd3518ad 100644
--- a/packages/raystack/components/chip/chip.tsx
+++ b/packages/raystack/components/chip/chip.tsx
@@ -1,7 +1,7 @@
'use client';
import { cva, type VariantProps } from 'class-variance-authority';
-import { ReactNode } from 'react';
+import { ComponentProps, ReactNode } from 'react';
import styles from './chip.module.css';
@@ -27,19 +27,15 @@ const chip = cva(styles.chip, {
}
});
-type ChipProps = VariantProps & {
- trailingIcon?: ReactNode;
- leadingIcon?: ReactNode;
- isDismissible?: boolean;
- children: ReactNode;
- className?: string;
- onDismiss?: () => void;
- onClick?: () => void;
- role?: string;
- ariaLabel?: string;
- disabled?: boolean;
- 'data-state'?: string;
-};
+type ChipProps = ComponentProps<'span'> &
+ VariantProps & {
+ trailingIcon?: ReactNode;
+ leadingIcon?: ReactNode;
+ isDismissible?: boolean;
+ children: ReactNode;
+ onDismiss?: () => void;
+ disabled?: boolean;
+ };
export const Chip = ({
variant,
@@ -53,9 +49,9 @@ export const Chip = ({
onDismiss,
onClick,
role = 'status',
- ariaLabel,
disabled,
- 'data-state': dataState
+ 'aria-label': ariaLabel,
+ ...props
}: ChipProps) => {
const handleDismiss = (e: React.MouseEvent) => {
e.stopPropagation();
@@ -64,14 +60,14 @@ export const Chip = ({
return (
{leadingIcon && (
{
expect(input).toHaveValue('initial value');
});
});
+
+ describe('Forwarded HTML attributes', () => {
+ it('forwards arbitrary HTML attributes onto the root div', () => {
+ render(
+
+ );
+
+ const root = screen.getByTestId('filter-root');
+ expect(root).toHaveAttribute('id', 'my-filter');
+ expect(root).toHaveAttribute('title', 'Tooltip');
+ });
+ });
});
diff --git a/packages/raystack/components/filter-chip/filter-chip.tsx b/packages/raystack/components/filter-chip/filter-chip.tsx
index 1ab910194..03942b760 100644
--- a/packages/raystack/components/filter-chip/filter-chip.tsx
+++ b/packages/raystack/components/filter-chip/filter-chip.tsx
@@ -2,7 +2,7 @@
import { Cross1Icon } from '@radix-ui/react-icons';
import { cva, cx, VariantProps } from 'class-variance-authority';
-import { ReactElement, ReactNode, useCallback, useState } from 'react';
+import { ComponentProps, ReactElement, useCallback, useState } from 'react';
import {
FilterOperation,
FilterOperator,
@@ -32,13 +32,12 @@ const chip = cva(styles.chip, {
}
});
-export interface FilterChipProps extends VariantProps {
+export interface FilterChipProps
+ extends ComponentProps<'div'>,
+ VariantProps {
label: string;
value?: string;
onRemove?: () => void;
- className?: string;
- ref?: React.RefObject;
- children?: ReactNode;
columnType?: FilterTypes;
options?: FilterSelectOption[];
onValueChange?: (value: any, operation: string) => void;