Skip to content

Commit 84c44ae

Browse files
Merge pull request #637 from thejackshelton/feat/select
docs(select): select docs
2 parents 3a6e457 + 2bc8149 commit 84c44ae

File tree

25 files changed

+506
-104
lines changed

25 files changed

+506
-104
lines changed

.changeset/tidy-coats-admire.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
## Select component hits beta!
6+
7+
## Features
8+
9+
- Accessible as a button that shows a list, following web a11y standards.
10+
- Support for single selection.
11+
- Controlled or uncontrolled.
12+
- Disabled option support.
13+
- Stop focus management via the Tab key.
14+
- Grouped options support.
15+
- Looping support.
16+
- Support for custom scroll behavior.
17+
- Listbox UI is placed above everything else. (SelectPopover)
18+
- Custom Positioning (SelectPopover)
19+
- Option selection and focus management by typing (typeahead).
20+
- Keyboard support for option navigation via arrow keys and focus management.
21+
- Automatic focus management for first and last options.
22+
- Supports a custom placeholder.
23+
24+
## Roadmap
25+
26+
- Opt-in native form support via a visually hidden select.
27+
- RTL support.
28+
- Multiple Selection and its respective keyboard interactions.

apps/website/src/_state/component-statuses.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const statusByComponent: ComponentKitsStatuses = {
3737
Modal: ComponentStatus.Beta,
3838
Pagination: ComponentStatus.Draft,
3939
Popover: ComponentStatus.Beta,
40-
Select: ComponentStatus.Draft,
40+
Select: ComponentStatus.Beta,
4141
Separator: ComponentStatus.Beta,
4242
Tabs: ComponentStatus.Beta,
4343
Tooltip: ComponentStatus.Draft,

apps/website/src/components/feature-list/feature-list.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { component$ } from '@builder.io/qwik';
22
import { CheckIcon } from '../icons/Check';
3+
import { Roadmap } from '../icons/Roadmap';
34

45
type FeatureListProps = {
56
features: string[];
7+
roadmap?: string[];
68
};
79

810
export const FeatureList = component$((props: FeatureListProps) => {
@@ -19,6 +21,24 @@ export const FeatureList = component$((props: FeatureListProps) => {
1921
</li>
2022
);
2123
})}
24+
{props.roadmap && (
25+
<>
26+
<h3 class="mb-6 mt-8 scroll-mt-20 text-xl font-semibold">Roadmap</h3>
27+
{props.roadmap.map((descriptor) => {
28+
return (
29+
<>
30+
<li
31+
key={descriptor}
32+
class="flex w-full list-none items-center gap-x-2 gap-y-4 border-b-[1px] border-slate-200 py-2 dark:border-slate-800"
33+
>
34+
<Roadmap class="min-w-[21px]" />
35+
{descriptor}
36+
</li>
37+
</>
38+
);
39+
})}
40+
</>
41+
)}
2242
</ul>
2343
);
2444
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { QwikIntrinsicElements } from '@builder.io/qwik';
2+
3+
export function Roadmap(props: QwikIntrinsicElements['svg'], key: string) {
4+
return (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
width="1.35em"
8+
height="1.35em"
9+
viewBox="0 0 256 256"
10+
{...props}
11+
key={key}
12+
>
13+
<g fill="#F9C23C">
14+
<path d="M224 128a96 96 0 1 1-96-96a96 96 0 0 1 96 96" opacity=".2"></path>
15+
<path d="M96.26 37a8 8 0 0 1 5.74-9.71a104.11 104.11 0 0 1 52 0a8 8 0 0 1-2 15.75a8.15 8.15 0 0 1-2-.26a88.09 88.09 0 0 0-44 0A8 8 0 0 1 96.26 37M53.79 55.14a104 104 0 0 0-26 45a8 8 0 1 0 15.42 4.26a87.91 87.91 0 0 1 22-38.08a8 8 0 0 0-11.42-11.18m-10.58 96.41a8 8 0 1 0-15.42 4.28a104 104 0 0 0 26 45a8 8 0 1 0 11.41-11.21a88.14 88.14 0 0 1-21.99-38.07M150 213.22a88 88 0 0 1-44 0a8 8 0 1 0-4 15.49a104.11 104.11 0 0 0 52 0a8 8 0 0 0-4-15.49M222.65 146a8 8 0 0 0-9.85 5.57a87.88 87.88 0 0 1-22 38.09a8 8 0 1 0 11.42 11.21a104.05 104.05 0 0 0 26-45a8 8 0 0 0-5.57-9.87m-9.86-41.54a8 8 0 0 0 15.42-4.28a104 104 0 0 0-26-45a8 8 0 1 0-11.41 11.21a88.14 88.14 0 0 1 21.99 38.06Z"></path>
16+
</g>
17+
</svg>
18+
);
19+
}
20+
export default Roadmap;

apps/website/src/routes/docs/headless/select/examples/add-users.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import styles from './select.css?inline';
1111

1212
export default component$(() => {
1313
useStyles$(styles);
14-
const usersSig = useSignal<string[]>(['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby']);
15-
const hasAddedUsersSig = useSignal<boolean>(false);
14+
const users = useSignal<string[]>(['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby']);
15+
const hasAddededUsers = useSignal<boolean>(false);
1616

1717
return (
1818
<>
@@ -22,19 +22,17 @@ export default component$(() => {
2222
</SelectTrigger>
2323
<SelectPopover class="select-popover">
2424
<SelectListbox class="select-listbox">
25-
{usersSig.value.map((user) => (
26-
<SelectOption class="select-option" key={user}>
27-
{user}
28-
</SelectOption>
25+
{users.value.map((user) => (
26+
<SelectOption key={user}>{user}</SelectOption>
2927
))}
3028
</SelectListbox>
3129
</SelectPopover>
3230
</Select>
3331
<button
3432
onClick$={$(() => {
35-
if (!hasAddedUsersSig.value) {
36-
usersSig.value = [...usersSig.value, 'John', 'Jane', 'Bob'];
37-
hasAddedUsersSig.value = true;
33+
if (!hasAddededUsers.value) {
34+
users.value = [...users.value, 'John', 'Jane', 'Bob'];
35+
hasAddededUsers.value = true;
3836
}
3937
})}
4038
>

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ export default component$(() => {
2626
<SelectPopover class="select-popover">
2727
<SelectListbox class="select-listbox">
2828
{users.map((user) => (
29-
<SelectOption class="select-option" key={user}>
30-
{user}
31-
</SelectOption>
29+
<SelectOption key={user}>{user}</SelectOption>
3230
))}
3331
</SelectListbox>
3432
</SelectPopover>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default component$(() => {
2828
<SelectPopover class="select-popover">
2929
<SelectListbox class="select-listbox">
3030
{users.map((user, index) => (
31-
<SelectOption value={index.toString()} class="select-option" key={user}>
31+
<SelectOption value={index.toString()} key={user}>
3232
{user}
3333
</SelectOption>
3434
))}

apps/website/src/routes/docs/headless/select/examples/controlled.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ export default component$(() => {
2828
<SelectPopover class="select-popover">
2929
<SelectListbox class="select-listbox">
3030
{users.map((user) => (
31-
<SelectOption class="select-option" key={user}>
32-
{user}
33-
</SelectOption>
31+
<SelectOption key={user}>{user}</SelectOption>
3432
))}
3533
</SelectListbox>
3634
</SelectPopover>

apps/website/src/routes/docs/headless/select/examples/disabled.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export default component$(() => {
2323
<SelectListbox class="select-listbox">
2424
{users.map((user, index) => (
2525
<SelectOption
26-
class="select-option"
2726
key={user}
2827
disabled={
2928
index === 0 || index === 2 || index === users.length - 1 ? true : false

apps/website/src/routes/docs/headless/select/examples/group.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ export default component$(() => {
2626
<SelectGroup>
2727
<SelectLabel class="select-label">People</SelectLabel>
2828
{users.map((user) => (
29-
<SelectOption class="select-option" key={user}>
30-
{user}
31-
</SelectOption>
29+
<SelectOption key={user}>{user}</SelectOption>
3230
))}
3331
</SelectGroup>
3432
<SelectGroup>

apps/website/src/routes/docs/headless/select/examples/hero.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ export default component$(() => {
2121
<SelectPopover class="select-popover">
2222
<SelectListbox class="select-listbox">
2323
{users.map((user) => (
24-
<SelectOption class="select-option" key={user}>
25-
{user}
26-
</SelectOption>
24+
<SelectOption key={user}>{user}</SelectOption>
2725
))}
2826
</SelectListbox>
2927
</SelectPopover>

apps/website/src/routes/docs/headless/select/examples/loop.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ export default component$(() => {
2121
<SelectPopover class="select-popover">
2222
<SelectListbox class="select-listbox">
2323
{users.map((user) => (
24-
<SelectOption class="select-option" key={user}>
25-
{user}
26-
</SelectOption>
24+
<SelectOption key={user}>{user}</SelectOption>
2725
))}
2826
</SelectListbox>
2927
</SelectPopover>

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

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
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 './select.css?inline';
11+
12+
export default component$(() => {
13+
useStyles$(styles);
14+
const users = [
15+
{ name: 'Tim', status: '🟢' },
16+
{ name: 'Ryan', status: '🔴' },
17+
{ name: 'Jim', status: '🟡' },
18+
{ name: 'Jessie', status: '🟢' },
19+
{ name: 'Abby', status: '🟡' },
20+
];
21+
22+
return (
23+
<Select class="select">
24+
<SelectTrigger class="select-trigger">
25+
<SelectValue placeholder="Select an option" />
26+
</SelectTrigger>
27+
<SelectPopover class="select-popover">
28+
<SelectListbox class="select-listbox">
29+
{users.map((user) => {
30+
return (
31+
<SelectOption key={user.name}>{`${user.status} ${user.name}`}</SelectOption>
32+
);
33+
})}
34+
</SelectListbox>
35+
</SelectPopover>
36+
</Select>
37+
);
38+
});

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ export default component$(() => {
2929
<SelectPopover class="select-popover">
3030
<SelectListbox class="select-listbox">
3131
{users.map((user) => (
32-
<SelectOption class="select-option" key={user}>
33-
{user}
34-
</SelectOption>
32+
<SelectOption key={user}>{user}</SelectOption>
3533
))}
3634
</SelectListbox>
3735
</SelectPopover>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default component$(() => {
3333
<SelectPopover class="select-popover">
3434
<SelectListbox class="select-listbox">
3535
{users.map((user) => (
36-
<SelectOption value={user.id} class="select-option" key={user.id}>
36+
<SelectOption value={user.id} key={user.id}>
3737
{user.label}
3838
</SelectOption>
3939
))}

apps/website/src/routes/docs/headless/select/examples/scrollable.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ export default component$(() => {
3434
<SelectGroup>
3535
<SelectLabel class="select-label">Animals</SelectLabel>
3636
{animals.map((animal) => (
37-
<SelectOption class="select-option" key={animal}>
38-
{animal}
39-
</SelectOption>
37+
<SelectOption key={animal}>{animal}</SelectOption>
4038
))}
4139
</SelectGroup>
4240
</SelectListbox>

apps/website/src/routes/docs/headless/select/examples/select.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
padding: 0.5rem;
2525
border: 2px dashed hsla(var(--foreground) / 0.6);
2626
border-radius: calc(var(--border-radius) / 2);
27-
z-index: 9999;
2827
max-width: var(--select-width);
2928
color: hsl(var(--foreground));
3029
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
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 './select.css?inline';
11+
12+
export default component$(() => {
13+
useStyles$(styles);
14+
15+
return (
16+
<Select class="select">
17+
<SelectTrigger class="select-trigger">
18+
<SelectValue placeholder="Select an option" />
19+
</SelectTrigger>
20+
<SelectPopover class="select-popover">
21+
<SelectListbox class="select-listbox">
22+
<SelectOption>Option 1</SelectOption>
23+
<SelectOption>Option 2</SelectOption>
24+
</SelectListbox>
25+
</SelectPopover>
26+
</Select>
27+
);
28+
});

apps/website/src/routes/docs/headless/select/examples/typeahead.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ export default component$(() => {
2121
<SelectPopover class="select-popover">
2222
<SelectListbox class="select-listbox">
2323
{users.map((user) => (
24-
<SelectOption class="select-option" key={user}>
25-
{user}
26-
</SelectOption>
24+
<SelectOption key={user}>{user}</SelectOption>
2725
))}
2826
</SelectListbox>
2927
</SelectPopover>

apps/website/src/routes/docs/headless/select/examples/uncontrolled.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ export default component$(() => {
2121
<SelectPopover class="select-popover">
2222
<SelectListbox class="select-listbox">
2323
{users.map((user) => (
24-
<SelectOption class="select-option" key={user}>
25-
{user}
26-
</SelectOption>
24+
<SelectOption key={user}>{user}</SelectOption>
2725
))}
2826
</SelectListbox>
2927
</SelectPopover>

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

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,17 @@ export default component$(() => {
1414
const users = ['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby'];
1515

1616
return (
17-
<>
18-
<Select value="Jessi" class="select">
19-
<SelectTrigger class="select-trigger">
20-
<SelectValue placeholder="wrong value placeholder" />
21-
</SelectTrigger>
22-
<SelectPopover class="select-popover">
23-
<SelectListbox class="select-listbox">
24-
{users.map((user) => (
25-
<SelectOption class="select-option" key={user}>
26-
{user}
27-
</SelectOption>
28-
))}
29-
</SelectListbox>
30-
</SelectPopover>
31-
</Select>
32-
</>
17+
<Select value="Jessi" class="select">
18+
<SelectTrigger class="select-trigger">
19+
<SelectValue placeholder="wrong value placeholder" />
20+
</SelectTrigger>
21+
<SelectPopover class="select-popover">
22+
<SelectListbox class="select-listbox">
23+
{users.map((user) => (
24+
<SelectOption key={user}>{user}</SelectOption>
25+
))}
26+
</SelectListbox>
27+
</SelectPopover>
28+
</Select>
3329
);
3430
});

0 commit comments

Comments
 (0)