Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions apps/www/src/content/docs/components/search/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ The Search component can include a clear button that appears when there is input

<Demo data={clearDemo} />

### Clearing

Escape clears the input when it has a value. After a clear, from the clear button or from Escape, focus is on the input and `onClear` receives the triggering event.

When you pass `value` and `onClear`, `onClear` must reset `value`. In every other case, a clear empties the input and fires `onChange` and `onValueChange` with an empty value. Escape clears whether or not `showClearButton` is set.

When the input is empty, Escape is not handled, so it can close an enclosing Dialog, Popover, or Menu.

### Controlled value

Use `onValueChange` to receive only the new query string, or `onChange` for the full React change event. The Search component forwards both to the underlying [Input](/docs/components/input).
Expand Down Expand Up @@ -84,3 +92,4 @@ The component supports keyboard navigation:
- Tab to focus on the search input
- Tab again to focus on the clear button (when visible)
- Enter or Space to trigger the clear button
- Escape to clear the input when it has a value
16 changes: 14 additions & 2 deletions apps/www/src/content/docs/components/search/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@ export interface SearchProps {
*/
onValueChange?: (value: string, eventDetails: unknown) => void;

/** Callback when clear button is clicked. */
onClear?: () => void;
/**
* Called when the clear button is clicked or Escape clears the input. Receives the triggering event.
*/
onClear?: (
event:
| React.MouseEvent<HTMLButtonElement>
| React.KeyboardEvent<HTMLInputElement>
) => void;

/**
* Native input type. The default gives the input the `searchbox` role.
* @default "search"
*/
type?: string;

/** Additional CSS class names. */
className?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ describe('DataView', () => {
</DataView>
);
// Search input
expect(screen.getByRole('textbox')).toBeInTheDocument();
expect(screen.getByRole('searchbox')).toBeInTheDocument();
// Filter button
expect(
screen.getByRole('button', { name: /filter/i })
Expand All @@ -374,7 +374,7 @@ describe('DataView', () => {
<DataView.List variant='table' columns={mockColumns} />
</DataView>
);
const search = screen.getByRole('textbox') as HTMLInputElement;
const search = screen.getByRole('searchbox') as HTMLInputElement;
await user.type(search, 'jane');
expect(search.value).toBe('jane');
// John row should no longer appear (client-mode global filter)
Expand Down Expand Up @@ -794,7 +794,7 @@ describe('DataView', () => {
<DataView.List variant='table' columns={mockColumns} />
</DataView>
);
await user.type(screen.getByRole('textbox'), 'jane');
await user.type(screen.getByRole('searchbox'), 'jane');
expect(onTableQueryChange).not.toHaveBeenCalled();
});

Expand All @@ -815,7 +815,7 @@ describe('DataView', () => {
<DataView.List variant='table' columns={mockColumns} />
</DataView>
);
await user.type(screen.getByRole('textbox'), 'a');
await user.type(screen.getByRole('searchbox'), 'a');
expect(onTableQueryChange).toHaveBeenCalled();
const calls = onTableQueryChange.mock.calls;
const lastCall = calls[calls.length - 1]?.[0];
Expand Down
Loading
Loading