> For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt.

# SearchModal

A command-palette dialog opened with Cmd+K (Ctrl+K on Windows/Linux). Provides a search input, grouped item lists, keyboard navigation, and a footer with keyboard hints. Content is consumer-assembled: the component is a composable shell, not a hard-wired feature.

[Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/SearchModal) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/navigation-searchmodal--overview)

```tsx
import { useMemo, useState } from 'react';
import { ChevronRight, Plus, Search, Users } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';
import { WallyIcon } from '@wallarm-org/design-system/WallyIcon';

export const Basic = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const filteredRecents = useMemo(() => filterItems(RECENT_ITEMS, query), [query]);
  const filteredJumpTo = useMemo(() => filterItems(JUMP_TO_ITEMS, query), [query]);
  const hasResults = filteredRecents.length > 0 || filteredJumpTo.length > 0;

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery} data-testid='search'>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Search products, features, and more\u2026' />
        <SearchModalBody>
          <SearchModalGroup>
            <SearchModalGroupLabel>
              <Text size='xs' color='secondary' weight='medium'>
                Quick actions
              </Text>
            </SearchModalGroupLabel>
            <SearchModalItem onSelect={noop}>
              <WallyIcon variant='circle' size='sm' />
              <Text size='sm'>{query ? `Ask Wally "${query}"` : 'Ask Wally'}</Text>
            </SearchModalItem>
            {!query && (
              <>
                <SearchModalItem onSelect={noop}>
                  <Users className='!icon-md' />
                  <Text size='sm'>Switch tenant</Text>
                </SearchModalItem>
                <SearchModalItem onSelect={noop}>
                  <Plus className='!icon-md' />
                  <Text size='sm'>Create&hellip;</Text>
                </SearchModalItem>
              </>
            )}
          </SearchModalGroup>

          {filteredRecents.length > 0 && (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  Recent
                </Text>
              </SearchModalGroupLabel>
              {filteredRecents.map(item => (
                <SearchModalItem key={item.id} onSelect={noop}>
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                  <span className='ml-auto'>
                    <Text size='xs' color='secondary'>
                      {item.date}
                    </Text>
                  </span>
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          )}

          {(hasResults || !query) && (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  {query ? 'Go to' : 'Jump to'}
                </Text>
              </SearchModalGroupLabel>
              {(query ? filteredJumpTo : JUMP_TO_ITEMS).map(item => (
                <SearchModalItem key={item.id} onSelect={noop}>
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                  <ChevronRight className='text-text-tertiary ml-auto !icon-sm' />
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          )}

          {query && !hasResults && (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

## Usage

```tsx
import { ChevronRight, Plus, Search, Users } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';
import { WallyIcon } from '@wallarm-org/design-system/WallyIcon';
```

## Examples

### Empty recents

A new user with no history. The Recent section shows "Nothing recent yet"
instead of items. Matches PRD state 2.

```tsx
import { useMemo, useState } from 'react';
import { ChevronRight, Plus, Search, Users } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';
import { WallyIcon } from '@wallarm-org/design-system/WallyIcon';

export const EmptyRecents = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const filteredJumpTo = useMemo(() => filterItems(JUMP_TO_ITEMS, query), [query]);

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Search products, features, and more\u2026' />
        <SearchModalBody>
          <SearchModalGroup>
            <SearchModalGroupLabel>
              <Text size='xs' color='secondary' weight='medium'>
                Quick actions
              </Text>
            </SearchModalGroupLabel>
            <SearchModalItem onSelect={noop}>
              <WallyIcon variant='circle' size='sm' />
              <Text size='sm'>{query ? `Ask Wally "${query}"` : 'Ask Wally'}</Text>
            </SearchModalItem>
            {!query && (
              <>
                <SearchModalItem onSelect={noop}>
                  <Users className='!icon-md' />
                  <Text size='sm'>Switch tenant</Text>
                </SearchModalItem>
                <SearchModalItem onSelect={noop}>
                  <Plus className='!icon-md' />
                  <Text size='sm'>Create&hellip;</Text>
                </SearchModalItem>
              </>
            )}
          </SearchModalGroup>

          {!query && (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  Recent
                </Text>
              </SearchModalGroupLabel>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  Nothing recent yet
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}

          {filteredJumpTo.length > 0 && (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  {query ? 'Go to' : 'Jump to'}
                </Text>
              </SearchModalGroupLabel>
              {filteredJumpTo.map(item => (
                <SearchModalItem key={item.id} onSelect={noop}>
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                  <ChevronRight className='text-text-tertiary ml-auto !icon-sm' />
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          )}

          {query && filteredJumpTo.length === 0 && (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

### Sub list

A sub-list page pushed in place of the main body. Used for "Create\u2026" and
"Switch tenant". The footer changes to show "esc back" and "enter to select".
Demonstrates PRD states 6 and 7.

```tsx
import { useMemo, useState } from 'react';
import { Kbd } from '@wallarm-org/design-system/Kbd';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';

export const SubList = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const filtered = useMemo(() => filterItems(CREATE_ITEMS, query), [query]);
  const grouped = useMemo(() => {
    const map = new Map<string, NavItem[]>();
    for (const item of filtered) {
      const key = item.section ?? 'Other';
      const list = map.get(key);
      if (list) list.push(item);
      else map.set(key, [item]);
    }
    return map;
  }, [filtered]);

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Filter creatable items\u2026' />
        <SearchModalBody>
          {filtered.length > 0 ? (
            [...grouped.entries()].map(([section, items]) => (
              <SearchModalGroup key={section}>
                <SearchModalGroupLabel>
                  <Text size='xs' color='secondary' weight='medium'>
                    {section}
                  </Text>
                </SearchModalGroupLabel>
                {items.map(item => (
                  <SearchModalItem key={item.id} onSelect={noop}>
                    {item.icon}
                    <Text size='sm'>{item.label}</Text>
                  </SearchModalItem>
                ))}
              </SearchModalGroup>
            ))
          ) : (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter>
          <span className='inline-flex items-center gap-4'>
            <Kbd size='xsmall'>esc</Kbd>
            <Text size='xs' color='secondary'>
              back
            </Text>
          </span>
          <span className='inline-flex items-center gap-4'>
            <Kbd size='xsmall'>&crarr;</Kbd>
            <Text size='xs' color='secondary'>
              to select
            </Text>
          </span>
        </SearchModalFooter>
      </SearchModalContent>
    </SearchModal>
  );
};
```

### Items as links

Items rendered as links via `asChild`, for cases where results navigate to a URL.

```tsx
import { useMemo, useState } from 'react';
import { ChevronRight, Search } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';

export const ItemsAsLinks = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const filtered = useMemo(() => filterItems(JUMP_TO_ITEMS, query), [query]);

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Search products, features, and more\u2026' />
        <SearchModalBody>
          {filtered.length > 0 ? (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  {query ? 'Go to' : 'Jump to'}
                </Text>
              </SearchModalGroupLabel>
              {filtered.map(item => (
                <SearchModalItem key={item.id} asChild onSelect={noop}>
                  <a href={`#${item.id}`}>
                    {item.icon}
                    <Text size='sm'>{item.label}</Text>
                    <ChevronRight className='text-text-tertiary ml-auto !icon-sm' />
                  </a>
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          ) : (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

### Disabled items

Disabled items are excluded from keyboard navigation and cannot be selected.

```tsx
import { useMemo, useState } from 'react';
import { Plus, Search, Users } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';
import { WallyIcon } from '@wallarm-org/design-system/WallyIcon';

export const DisabledItems = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const actions = useMemo(
    () =>
      filterItems(
        [
          { id: 'ask-wally', label: 'Ask Wally', icon: <WallyIcon variant='circle' size='sm' /> },
          { id: 'switch-tenant', label: 'Switch tenant', icon: <Users className='!icon-md' /> },
          { id: 'create', label: 'Create\u2026', icon: <Plus className='!icon-md' /> },
        ],
        query,
      ),
    [query],
  );

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Search products, features, and more\u2026' />
        <SearchModalBody>
          {actions.length > 0 ? (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  Quick actions
                </Text>
              </SearchModalGroupLabel>
              {actions.map(item => (
                <SearchModalItem
                  key={item.id}
                  onSelect={item.id === 'switch-tenant' ? undefined : noop}
                  disabled={item.id === 'switch-tenant'}
                >
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                  {item.id === 'switch-tenant' && (
                    <span className='ml-auto'>
                      <Text size='xs' color='secondary'>
                        Unavailable
                      </Text>
                    </span>
                  )}
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          ) : (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

### Close on select false

`closeOnSelect={false}` keeps the modal open after selecting an item, useful
for multi-step flows like the sub-list mechanic.

```tsx
import { useCallback, useMemo, useState } from 'react';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';

export const CloseOnSelectFalse = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');
  const [selected, setSelected] = useState<string[]>([]);

  const filtered = useMemo(() => filterItems(JUMP_TO_ITEMS, query), [query]);

  const toggleItem = useCallback(
    (id: string) =>
      setSelected(prev => (prev.includes(id) ? prev.filter(v => v !== id) : [...prev, id])),
    [],
  );

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Pick items (modal stays open)\u2026' />
        <SearchModalBody>
          {filtered.length > 0 ? (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  Products {selected.length > 0 && `(${selected.length} selected)`}
                </Text>
              </SearchModalGroupLabel>
              {filtered.map(item => (
                <SearchModalItem
                  key={item.id}
                  closeOnSelect={false}
                  onSelect={() => toggleItem(item.id)}
                >
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                  {selected.includes(item.id) && (
                    <span className='ml-auto'>
                      <Text size='xs' color='primary-alt'>
                        Selected
                      </Text>
                    </span>
                  )}
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          ) : (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

### Controlled

Controlled open state, driven entirely from outside the component.
No `SearchModalTrigger` — the button calls `setOpen` directly.

```tsx
import { useMemo, useState } from 'react';
import { Button } from '@wallarm-org/design-system/Button';
import { Search } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';

export const Controlled = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const filtered = useMemo(() => filterItems(JUMP_TO_ITEMS, query), [query]);

  return (
    <>
      <Button variant='outline' color='neutral' onClick={() => setOpen(true)}>
        Open Programmatically
      </Button>
      <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
        <SearchModalContent>
          <SearchModalInput placeholder='Search products, features, and more\u2026' />
          <SearchModalBody>
            {filtered.length > 0 ? (
              <SearchModalGroup>
                <SearchModalGroupLabel>
                  <Text size='xs' color='secondary' weight='medium'>
                    {query ? 'Go to' : 'Jump to'}
                  </Text>
                </SearchModalGroupLabel>
                {filtered.map(item => (
                  <SearchModalItem key={item.id} onSelect={noop}>
                    {item.icon}
                    <Text size='sm'>{item.label}</Text>
                  </SearchModalItem>
                ))}
              </SearchModalGroup>
            ) : (
              <SearchModalGroup>
                <SearchModalEmpty>
                  <Text size='sm' color='secondary'>
                    No results
                  </Text>
                </SearchModalEmpty>
              </SearchModalGroup>
            )}
          </SearchModalBody>
          <SearchModalFooter />
        </SearchModalContent>
      </SearchModal>
    </>
  );
};
```

### Scrollable

The scrollable body when there are many items. The input and footer stay fixed
while the body scrolls.

```tsx
import { useMemo, useState } from 'react';
import { Compass, Search } from '@wallarm-org/design-system/icons';
import { SearchModal, SearchModalBody, SearchModalContent, SearchModalEmpty, SearchModalFooter, SearchModalGroup, SearchModalGroupLabel, SearchModalInput, SearchModalItem } from '@wallarm-org/design-system/SearchModal';
import { Text } from '@wallarm-org/design-system/Text';

export const Scrollable = () => {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');

  const allItems = useMemo(
    () =>
      Array.from({ length: 30 }, (_, i) => ({
        id: `item-${i}`,
        label: `Feature ${i + 1}`,
        icon: <Compass className='text-text-primary !icon-md' />,
      })),
    [],
  );

  const filtered = useMemo(() => filterItems(allItems, query), [allItems, query]);

  return (
    <SearchModal open={open} onOpenChange={setOpen} onQueryChange={setQuery}>
      <SearchTriggerButton />
      <SearchModalContent>
        <SearchModalInput placeholder='Search products, features, and more\u2026' />
        <SearchModalBody>
          {filtered.length > 0 ? (
            <SearchModalGroup>
              <SearchModalGroupLabel>
                <Text size='xs' color='secondary' weight='medium'>
                  All features
                </Text>
              </SearchModalGroupLabel>
              {filtered.map(item => (
                <SearchModalItem key={item.id} onSelect={noop}>
                  {item.icon}
                  <Text size='sm'>{item.label}</Text>
                </SearchModalItem>
              ))}
            </SearchModalGroup>
          ) : (
            <SearchModalGroup>
              <SearchModalEmpty>
                <Text size='sm' color='secondary'>
                  No results
                </Text>
              </SearchModalEmpty>
            </SearchModalGroup>
          )}
        </SearchModalBody>
        <SearchModalFooter />
      </SearchModalContent>
    </SearchModal>
  );
};
```

## Props

| Prop          | Type                                     | Default | Description |
| ------------- | ---------------------------------------- | ------- | ----------- |
| open          | `boolean \| undefined`                   |         |             |
| onOpenChange  | `((open: boolean) => void) \| undefined` |         |             |
| onQueryChange | `((query: string) => void) \| undefined` |         |             |
| data-testid   | `string \| undefined`                    |         |             |

### SearchModalBody

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalContent

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalEmpty

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalFooter

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalGroup

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalGroupLabel

| Prop           | Type                                                 | Default | Description |
| -------------- | ---------------------------------------------------- | ------- | ----------- |
| defaultChecked | `boolean \| undefined`                               |         |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |             |
| autoFocus      | `boolean \| undefined`                               |         |             |
| id             | `string \| undefined`                                |         |             |
| tabIndex       | `number \| undefined`                                |         |             |
| title          | `string \| undefined`                                |         |             |
| rel            | `string \| undefined`                                |         |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |             |

### SearchModalInput

| Prop           | Type                                                 | Default | Description                                      |
| -------------- | ---------------------------------------------------- | ------- | ------------------------------------------------ |
| loading        | `boolean \| undefined`                               | `false` | Show a loading spinner replacing the search icon |
| title          | `string \| undefined`                                |         |                                                  |
| pattern        | `string \| undefined`                                |         |                                                  |
| defaultChecked | `boolean \| undefined`                               |         |                                                  |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |                                                  |
| autoFocus      | `boolean \| undefined`                               |         |                                                  |
| id             | `string \| undefined`                                |         |                                                  |
| tabIndex       | `number \| undefined`                                |         |                                                  |
| rel            | `string \| undefined`                                |         |                                                  |
| type           | `HTMLInputTypeAttribute \| undefined`                |         |                                                  |
| disabled       | `boolean \| undefined`                               |         |                                                  |
| name           | `string \| undefined`                                |         |                                                  |
| alt            | `string \| undefined`                                |         |                                                  |
| height         | `string \| number \| undefined`                      |         |                                                  |
| src            | `string \| undefined`                                |         |                                                  |
| width          | `string \| number \| undefined`                      |         |                                                  |
| autoComplete   | `HTMLInputAutoCompleteAttribute \| undefined`        |         |                                                  |
| maxLength      | `number \| undefined`                                |         |                                                  |
| minLength      | `number \| undefined`                                |         |                                                  |
| placeholder    | `string \| undefined`                                |         |                                                  |
| readOnly       | `boolean \| undefined`                               |         |                                                  |
| required       | `boolean \| undefined`                               |         |                                                  |
| checked        | `boolean \| undefined`                               |         |                                                  |
| step           | `string \| number \| undefined`                      |         |                                                  |
| accept         | `string \| undefined`                                |         |                                                  |
| max            | `string \| number \| undefined`                      |         |                                                  |
| min            | `string \| number \| undefined`                      |         |                                                  |
| multiple       | `boolean \| undefined`                               |         |                                                  |

### SearchModalItem

| Prop           | Type                                                 | Default | Description                                                  |
| -------------- | ---------------------------------------------------- | ------- | ------------------------------------------------------------ |
| onSelect       | `(() => void) \| undefined`                          |         | Called when the item is selected (Enter key or click)        |
| disabled       | `boolean \| undefined`                               | `false` | Whether this item is disabled                                |
| asChild        | `boolean \| undefined`                               | `false` | Render as child element (e.g. for \<a> links)                |
| closeOnSelect  | `boolean \| undefined`                               | `true`  | Whether selecting this item closes the modal (default: true) |
| name           | `string \| undefined`                                |         |                                                              |
| type           | `"button" \| "submit" \| "reset" \| undefined`       |         |                                                              |
| value          | `string \| number \| readonly string[] \| undefined` |         |                                                              |
| defaultChecked | `boolean \| undefined`                               |         |                                                              |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |                                                              |
| autoFocus      | `boolean \| undefined`                               |         |                                                              |
| id             | `string \| undefined`                                |         |                                                              |
| tabIndex       | `number \| undefined`                                |         |                                                              |
| title          | `string \| undefined`                                |         |                                                              |
| rel            | `string \| undefined`                                |         |                                                              |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |                                                              |

### SearchModalTrigger

| Prop           | Type                                                 | Default | Description                                                                   |
| -------------- | ---------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
| asChild        | `boolean \| undefined`                               |         | Render as child element                                                       |
| value          | `string \| undefined`                                |         | Native button value attribute (string only, matching Ark UI's Dialog.Trigger) |
| title          | `string \| undefined`                                |         |                                                                               |
| defaultChecked | `boolean \| undefined`                               |         |                                                                               |
| defaultValue   | `string \| number \| readonly string[] \| undefined` |         |                                                                               |
| autoFocus      | `boolean \| undefined`                               |         |                                                                               |
| id             | `string \| undefined`                                |         |                                                                               |
| tabIndex       | `number \| undefined`                                |         |                                                                               |
| rel            | `string \| undefined`                                |         |                                                                               |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`        |         |                                                                               |
| type           | `"button" \| "submit" \| "reset" \| undefined`       |         |                                                                               |
| disabled       | `boolean \| undefined`                               |         |                                                                               |
| name           | `string \| undefined`                                |         |                                                                               |

## Explorer

