Skip to content

Commit 0725b2d

Browse files
Merge pull request #724 from thejackshelton/multi-select
multi-select functionality
2 parents f69f3c6 + f749710 commit 0725b2d

39 files changed

+1120
-774
lines changed

.changeset/silent-yaks-crash.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@qwik-ui/headless': minor
3+
---
4+
5+
**feat**: select now has a multi-select feature!
6+
7+
To opt-in to the multi-select mode, set the `multiple` prop to `true`. Please refer to the `Multiple Selections` section in the docs for more information.
8+
9+
**refactor**: `<SelectOption />` has been replaced with `<Select.ItemLabel />`.
10+
11+
The previous API did not allow for customization of list items. The new API introduces a new component:
12+
13+
```tsx
14+
<Select.Item>
15+
<Select.ItemLabel>My Display Option!</Select.ItemLabel>
16+
<Select.Item>
17+
```
18+
19+
You can now put anything you'd like in your `<Select.Item />`, just like a list item!
20+
21+
There is also another new component called `<Select.ItemIndicator />`. This component is used to render an icon or other visual element that is displayed next to the `<Select.ItemLabel />` whenever an item is selected.
22+
23+
**docs**: The docs have been updated to reflect the new API.

apps/website/src/routes/docs/headless/modal/examples/nested-popover.tsx

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Modal,
4-
Select,
5-
SelectPopover,
6-
SelectListbox,
7-
SelectOption,
8-
SelectTrigger,
9-
SelectValue,
10-
} from '@qwik-ui/headless';
2+
import { Modal, Select } from '@qwik-ui/headless';
113
import styles from '../snippets/modal.css?inline';
124

135
export default component$(() => {
@@ -21,17 +13,22 @@ export default component$(() => {
2113
</button>
2214
<Modal class="modal" bind:show={isOpen}>
2315
Modal Content
24-
<Select class="select">
25-
<SelectTrigger class="select-trigger">
26-
<SelectValue placeholder="Select an option" />
27-
</SelectTrigger>
28-
<SelectPopover class="select-popover">
29-
<SelectListbox class="select-listbox">
30-
<SelectOption>Option 1</SelectOption>
31-
<SelectOption>Option 2</SelectOption>
32-
</SelectListbox>
33-
</SelectPopover>
34-
</Select>
16+
<Select.Root class="select">
17+
<Select.Label>Logged in users</Select.Label>
18+
<Select.Trigger class="select-trigger">
19+
<Select.Value placeholder="Select an option" />
20+
</Select.Trigger>
21+
<Select.Popover class="select-popover">
22+
<Select.Listbox class="select-listbox">
23+
<Select.Item>
24+
<Select.ItemLabel>Option 1</Select.ItemLabel>
25+
</Select.Item>
26+
<Select.Item>
27+
<Select.ItemLabel>Option 2</Select.ItemLabel>
28+
</Select.Item>
29+
</Select.Listbox>
30+
</Select.Popover>
31+
</Select.Root>
3532
</Modal>
3633
</>
3734
);
Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import { $, component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectListbox,
5-
SelectOption,
6-
SelectPopover,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
10-
import styles from '../snippets/select.css?inline';
2+
import { Select } from '@qwik-ui/headless';
113

124
export default component$(() => {
135
useStyles$(styles);
@@ -16,18 +8,21 @@ export default component$(() => {
168

179
return (
1810
<>
19-
<Select class="select">
20-
<SelectTrigger class="select-trigger">
21-
<SelectValue placeholder="Select an option" />
22-
</SelectTrigger>
23-
<SelectPopover class="select-popover">
24-
<SelectListbox class="select-listbox">
11+
<Select.Root class="select">
12+
<Select.Label>Logged in users</Select.Label>
13+
<Select.Trigger class="select-trigger">
14+
<Select.Value placeholder="Select an option" />
15+
</Select.Trigger>
16+
<Select.Popover class="select-popover">
17+
<Select.Listbox class="select-listbox">
2518
{users.value.map((user) => (
26-
<SelectOption key={user}>{user}</SelectOption>
19+
<Select.Item key={user}>
20+
<Select.ItemLabel>{user}</Select.ItemLabel>
21+
</Select.Item>
2722
))}
28-
</SelectListbox>
29-
</SelectPopover>
30-
</Select>
23+
</Select.Listbox>
24+
</Select.Popover>
25+
</Select.Root>
3126
<button
3227
onClick$={$(() => {
3328
if (!hasAddedUsers.value) {
@@ -41,3 +36,6 @@ export default component$(() => {
4136
</>
4237
);
4338
});
39+
40+
// internal
41+
import styles from '../snippets/select.css?inline';
Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectListbox,
5-
SelectOption,
6-
SelectPopover,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
2+
import { Select } from '@qwik-ui/headless';
103
import styles from '../snippets/select.css?inline';
114

125
export default component$(() => {
@@ -17,18 +10,21 @@ export default component$(() => {
1710
return (
1811
<>
1912
<button onClick$={() => (isOpen.value = true)}>Toggle open state</button>
20-
<Select bind:open={isOpen} class="select">
21-
<SelectTrigger class="select-trigger">
22-
<SelectValue placeholder="Select an option" />
23-
</SelectTrigger>
24-
<SelectPopover class="select-popover">
25-
<SelectListbox class="select-listbox">
13+
<Select.Root bind:open={isOpen} class="select">
14+
<Select.Label>Logged in users</Select.Label>
15+
<Select.Trigger class="select-trigger">
16+
<Select.Value placeholder="Select an option" />
17+
</Select.Trigger>
18+
<Select.Popover class="select-popover">
19+
<Select.Listbox class="select-listbox">
2620
{users.map((user) => (
27-
<SelectOption key={user}>{user}</SelectOption>
21+
<Select.Item key={user}>
22+
<Select.ItemLabel>{user}</Select.ItemLabel>
23+
</Select.Item>
2824
))}
29-
</SelectListbox>
30-
</SelectPopover>
31-
</Select>
25+
</Select.Listbox>
26+
</Select.Popover>
27+
</Select.Root>
3228
</>
3329
);
3430
});

apps/website/src/routes/docs/headless/select/examples/change-value.tsx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import { $, component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectPopover,
5-
SelectListbox,
6-
SelectOption,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
2+
import { Select } from '@qwik-ui/headless';
103
import styles from '../snippets/select.css?inline';
114
export default component$(() => {
125
useStyles$(styles);
@@ -19,18 +12,21 @@ export default component$(() => {
1912

2013
return (
2114
<>
22-
<Select onChange$={handleChange$} class="select">
23-
<SelectTrigger class="select-trigger">
24-
<SelectValue placeholder="Select an option" />
25-
</SelectTrigger>
26-
<SelectPopover class="select-popover">
27-
<SelectListbox class="select-listbox">
15+
<Select.Root onChange$={handleChange$} class="select">
16+
<Select.Label>Logged in users</Select.Label>
17+
<Select.Trigger class="select-trigger">
18+
<Select.Value placeholder="Select an option" />
19+
</Select.Trigger>
20+
<Select.Popover class="select-popover">
21+
<Select.Listbox class="select-listbox">
2822
{users.map((user) => (
29-
<SelectOption key={user}>{user}</SelectOption>
23+
<Select.Item key={user}>
24+
<Select.ItemLabel>{user}</Select.ItemLabel>
25+
</Select.Item>
3026
))}
31-
</SelectListbox>
32-
</SelectPopover>
33-
</Select>
27+
</Select.Listbox>
28+
</Select.Popover>
29+
</Select.Root>
3430
<p>You have changed {counter.value} times</p>
3531
</>
3632
);
Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,31 @@
11
import { $, component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectPopover,
5-
SelectListbox,
6-
SelectOption,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
10-
import styles from '../snippets/select.css?inline';
2+
import { Select } from '@qwik-ui/headless';
113
export default component$(() => {
124
useStyles$(styles);
135
const users = ['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby'];
146
const selected = useSignal<string>('Ryan');
157

168
return (
179
<>
18-
<Select bind:value={selected} class="select">
19-
<SelectTrigger class="select-trigger">
20-
<SelectValue placeholder="Select an option" />
21-
</SelectTrigger>
22-
<SelectPopover class="select-popover">
23-
<SelectListbox class="select-listbox">
10+
<Select.Root bind:value={selected} class="select">
11+
<Select.Label>Logged in users</Select.Label>
12+
<Select.Trigger class="select-trigger">
13+
<Select.Value placeholder="Select an option" />
14+
</Select.Trigger>
15+
<Select.Popover class="select-popover">
16+
<Select.Listbox class="select-listbox">
2417
{users.map((user, index) => (
25-
<SelectOption value={index.toString()} key={user}>
26-
{user}
27-
</SelectOption>
18+
<Select.Item value={index.toString()} key={user}>
19+
<Select.ItemLabel>{user}</Select.ItemLabel>
20+
</Select.Item>
2821
))}
29-
</SelectListbox>
30-
</SelectPopover>
31-
</Select>
22+
</Select.Listbox>
23+
</Select.Popover>
24+
</Select.Root>
3225
<button onClick$={$(() => (selected.value = '4'))}>Change to Abby</button>
3326
</>
3427
);
3528
});
29+
30+
// internal
31+
import styles from '../snippets/select.css?inline';
Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,31 @@
1-
import { $, component$, useSignal, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectPopover,
5-
SelectListbox,
6-
SelectOption,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
10-
import styles from '../snippets/select.css?inline';
1+
import { component$, useSignal, useStyles$ } from '@builder.io/qwik';
2+
import { Select } from '@qwik-ui/headless';
113
export default component$(() => {
124
useStyles$(styles);
135
const users = ['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby'];
146
const selected = useSignal<string>('Ryan');
157

168
return (
179
<>
18-
<Select
19-
onChange$={$((value: string) => {
20-
selected.value = value;
21-
})}
22-
bind:value={selected}
23-
class="select"
24-
>
25-
<SelectTrigger class="select-trigger">
26-
<SelectValue placeholder="Select an option" />
27-
</SelectTrigger>
28-
<SelectPopover class="select-popover">
29-
<SelectListbox class="select-listbox">
10+
<Select.Root bind:value={selected} class="select">
11+
<Select.Label>Logged in users</Select.Label>
12+
<Select.Trigger class="select-trigger">
13+
<Select.Value placeholder="Select an option" />
14+
</Select.Trigger>
15+
<Select.Popover class="select-popover">
16+
<Select.Listbox class="select-listbox">
3017
{users.map((user) => (
31-
<SelectOption key={user}>{user}</SelectOption>
18+
<Select.Item key={user}>
19+
<Select.ItemLabel>{user}</Select.ItemLabel>
20+
</Select.Item>
3221
))}
33-
</SelectListbox>
34-
</SelectPopover>
35-
</Select>
22+
</Select.Listbox>
23+
</Select.Popover>
24+
</Select.Root>
3625
<p>Your favorite user is: {selected.value}</p>
3726
</>
3827
);
3928
});
29+
30+
// internal
31+
import styles from '../snippets/select.css?inline';
Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,34 @@
11
import { component$, useStyles$ } from '@builder.io/qwik';
2-
import {
3-
Select,
4-
SelectPopover,
5-
SelectListbox,
6-
SelectOption,
7-
SelectTrigger,
8-
SelectValue,
9-
} from '@qwik-ui/headless';
10-
import styles from '../snippets/select.css?inline';
2+
import { Select } from '@qwik-ui/headless';
113

124
export default component$(() => {
135
useStyles$(styles);
146
const users = ['Tim', 'Ryan', 'Jim', 'Bobbie', 'Joan', 'Jessie', 'Abby'];
157

168
return (
17-
<Select class="select">
9+
<Select.Root class="select">
1810
<p>This one is the disabled</p>
19-
<SelectTrigger class="select-trigger">
20-
<SelectValue placeholder="Select an option" />
21-
</SelectTrigger>
22-
<SelectPopover class="select-popover">
23-
<SelectListbox class="select-listbox">
11+
<Select.Label>Logged in users</Select.Label>
12+
<Select.Trigger class="select-trigger">
13+
<Select.Value placeholder="Select an option" />
14+
</Select.Trigger>
15+
<Select.Popover class="select-popover">
16+
<Select.Listbox class="select-listbox">
2417
{users.map((user, index) => (
25-
<SelectOption
18+
<Select.Item
2619
key={user}
2720
disabled={
2821
index === 0 || index === 2 || index === users.length - 1 ? true : false
2922
}
3023
>
31-
{user}
32-
</SelectOption>
24+
<Select.ItemLabel>{user}</Select.ItemLabel>
25+
</Select.Item>
3326
))}
34-
</SelectListbox>
35-
</SelectPopover>
36-
</Select>
27+
</Select.Listbox>
28+
</Select.Popover>
29+
</Select.Root>
3730
);
3831
});
32+
33+
// internal
34+
import styles from '../snippets/select.css?inline';

0 commit comments

Comments
 (0)