Skip to content

Commit c138a48

Browse files
Portal support and autocomplete deprecated
2 parents 1174068 + e3c8f18 commit c138a48

36 files changed

+2096
-375
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export const statusByComponent: ComponentKitsStatuses = {
4040
},
4141
headless: {
4242
Accordion: ComponentStatus.Beta,
43-
Autocomplete: ComponentStatus.Draft,
4443
Carousel: ComponentStatus.Planned,
44+
Combobox: ComponentStatus.Draft,
4545
Popover: ComponentStatus.Draft,
4646
Select: ComponentStatus.Draft,
4747
Tabs: ComponentStatus.Beta,

apps/website/src/routes/docs/headless/(components)/autocomplete/examples.tsx

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { component$, Slot } from '@builder.io/qwik';
1+
import { component$, Slot, useSignal } from '@builder.io/qwik';
22
import {
33
AutocompleteLabel,
44
AutocompleteRoot,
@@ -25,41 +25,59 @@ const trainers = [
2525
];
2626

2727
export const Example01 = component$(() => {
28+
const trainersSig = useSignal(trainers);
29+
const showExample = useSignal(true);
2830
return (
2931
<PreviewCodeExample>
30-
<div q:slot="actualComponent">
31-
<AutocompleteRoot class="relative">
32-
<AutocompleteLabel class=" font-semibold dark:text-white text-[#333333]">
33-
Personal Trainers ⚡
34-
</AutocompleteLabel>
35-
<AutocompleteControl class="bg-[#1f2532] flex items-center rounded-sm border-[#7d95b3] border-[1px] relative">
36-
<AutocompleteInput class="w-44 bg-inherit px-2 pr-6 text-white" />
37-
<AutocompleteTrigger class="w-6 h-6 group absolute right-0">
38-
<svg
39-
xmlns="http://www.w3.org/2000/svg"
40-
viewBox="0 0 24 24"
41-
fill="none"
42-
stroke-width="2"
43-
class="stroke-white group-aria-expanded:-rotate-180 transition-transform duration-[450ms]"
44-
stroke-linecap="round"
45-
stroke-linejoin="round"
46-
>
47-
<polyline points="6 9 12 15 18 9"></polyline>
48-
</svg>
49-
</AutocompleteTrigger>
50-
</AutocompleteControl>
51-
<AutocompleteListbox class="text-white w-full bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
52-
{trainers.map((trainer, index) => (
53-
<AutocompleteOption
54-
optionValue={trainer}
55-
key={index}
56-
class="rounded-sm px-2 hover:bg-[#496080] focus:bg-[#496080]"
57-
>
58-
{trainer}
59-
</AutocompleteOption>
60-
))}
61-
</AutocompleteListbox>
62-
</AutocompleteRoot>
32+
<div class="flex flex-col gap-4" q:slot="actualComponent">
33+
<button
34+
onClick$={() => {
35+
showExample.value = !showExample.value;
36+
}}
37+
>
38+
Show them
39+
</button>
40+
{showExample.value === true && (
41+
<AutocompleteRoot class="relative">
42+
<AutocompleteLabel class=" font-semibold dark:text-white text-[#333333]">
43+
Personal Trainers ⚡
44+
</AutocompleteLabel>
45+
<AutocompleteControl class="bg-[#1f2532] flex items-center rounded-sm border-[#7d95b3] border-[1px] relative">
46+
<AutocompleteInput class="w-44 bg-inherit px-2 pr-6 text-white" />
47+
<AutocompleteTrigger class="w-6 h-6 group absolute right-0">
48+
<svg
49+
xmlns="http://www.w3.org/2000/svg"
50+
viewBox="0 0 24 24"
51+
fill="none"
52+
stroke-width="2"
53+
class="stroke-white group-aria-expanded:-rotate-180 transition-transform duration-[450ms]"
54+
stroke-linecap="round"
55+
stroke-linejoin="round"
56+
>
57+
<polyline points="6 9 12 15 18 9"></polyline>
58+
</svg>
59+
</AutocompleteTrigger>
60+
</AutocompleteControl>
61+
<AutocompleteListbox class="text-white w-full bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
62+
{trainersSig.value.map((trainer) => (
63+
<AutocompleteOption
64+
optionValue={trainer}
65+
key={trainer}
66+
class="rounded-sm px-2 hover:bg-[#496080] focus:bg-[#496080]"
67+
>
68+
{trainer}
69+
</AutocompleteOption>
70+
))}
71+
</AutocompleteListbox>
72+
</AutocompleteRoot>
73+
)}
74+
<button
75+
onClick$={() => {
76+
trainersSig.value = ['One', 'Two', 'Three', 'Four', 'Five'];
77+
}}
78+
>
79+
Change them
80+
</button>
6381
</div>
6482

6583
<div q:slot="codeExample">
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { component$, Slot, useSignal } from '@builder.io/qwik';
2+
import {
3+
Combobox,
4+
ComboboxControl,
5+
ComboboxInput,
6+
ComboboxLabel,
7+
ComboboxListbox,
8+
ComboboxOption,
9+
ComboboxPortal,
10+
ComboboxTrigger
11+
} from '@qwik-ui/headless';
12+
13+
import { PreviewCodeExample } from '../../../_components/preview-code-example/preview-code-example';
14+
15+
const trainers = [
16+
'Caleb',
17+
'Olivia',
18+
'James',
19+
'Ava',
20+
'Noah',
21+
'Emma',
22+
'Oliver',
23+
'Amelia',
24+
'Theodore',
25+
'Elizabeth'
26+
];
27+
28+
export const Example01 = component$(() => {
29+
const trainersSig = useSignal(trainers);
30+
const showExample = useSignal(true);
31+
32+
return (
33+
<PreviewCodeExample>
34+
<div class="flex flex-col gap-4" q:slot="actualComponent">
35+
<button
36+
onClick$={() => {
37+
showExample.value = !showExample.value;
38+
}}
39+
>
40+
Show them
41+
</button>
42+
{showExample.value === true && (
43+
<Combobox class="relative">
44+
<ComboboxLabel class=" font-semibold dark:text-white text-[#333333]">
45+
Personal Trainers ⚡
46+
</ComboboxLabel>
47+
<ComboboxControl class="bg-[#1f2532] flex items-center rounded-sm border-[#7d95b3] border-[1px] relative">
48+
<ComboboxInput class="w-44 bg-inherit px-d2 pr-6 text-white" />
49+
<ComboboxTrigger class="w-6 h-6 group absolute right-0">
50+
<svg
51+
xmlns="http://www.w3.org/2000/svg"
52+
viewBox="0 0 24 24"
53+
fill="none"
54+
stroke-width="2"
55+
class="stroke-white group-aria-expanded:-rotate-180 transition-transform duration-[450ms]"
56+
stroke-linecap="round"
57+
stroke-linejoin="round"
58+
>
59+
<polyline points="6 9 12 15 18 9"></polyline>
60+
</svg>
61+
</ComboboxTrigger>
62+
</ComboboxControl>
63+
<ComboboxPortal>
64+
<ComboboxListbox class="text-white w-44 bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
65+
{trainersSig.value.map((trainer) => (
66+
<ComboboxOption
67+
key={trainer}
68+
class="rounded-sm px-2 hover:bg-[#496080] focus:bg-[#496080]"
69+
>
70+
{trainer}
71+
</ComboboxOption>
72+
))}
73+
</ComboboxListbox>
74+
</ComboboxPortal>
75+
</Combobox>
76+
)}
77+
<button
78+
onClick$={() => {
79+
trainersSig.value = ['One', 'Two', 'Three', 'Four', 'Five'];
80+
}}
81+
>
82+
Change them
83+
</button>
84+
</div>
85+
86+
<div q:slot="codeExample">
87+
<Slot />
88+
</div>
89+
</PreviewCodeExample>
90+
);
91+
});
92+
93+
export const Example02 = component$(() => {
94+
return <PreviewCodeExample></PreviewCodeExample>;
95+
});
96+
97+
export const Example03 = component$(() => {
98+
return <PreviewCodeExample></PreviewCodeExample>;
99+
});
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
title: Qwik UI | Combobox
3+
---
4+
5+
import {
6+
Combobox,
7+
ComboboxLabel,
8+
ComboboxTrigger,
9+
ComboboxInput,
10+
ComboboxListbox,
11+
ComboboxOption,
12+
} from '@qwik-ui/headless';
13+
14+
import { Example01, Example02, Example03 } from './examples';
15+
import { CodeExample } from '../../../_components/code-example/code-example';
16+
import { KeyboardInteractionTable } from '../../../_components/keyboard-interaction-table/keyboard-interaction-table';
17+
import { APITable } from '../../../_components/api-table/api-table';
18+
import { StatusBanner } from '../../../_components/status-banner/status-banner';
19+
import {statusByComponent} from '../../../../../_state/component-statuses';
20+
21+
<StatusBanner status={statusByComponent.headless.Combobox} />
22+
23+
# Combobox
24+
25+
#### A customizable text field with a listbox, enabling users to narrow down a list of choices based on their search criteria.
26+
27+
{' '}
28+
29+
<Example01>
30+
```tsx
31+
<Combobox class="relative text-white">
32+
<ComboboxLabel class="text-inherit font-semibold">
33+
Personal Trainers ⚡
34+
</ComboboxLabel>
35+
<ComboboxControl class="bg-[#1f2532] flex items-center rounded-sm border-[#7d95b3] border-[1px] relative">
36+
<ComboboxInput class="w-44 bg-inherit px-2 pr-6" />
37+
<ComboboxTrigger class="w-6 h-6 group absolute right-0">
38+
<svg
39+
xmlns="http://www.w3.org/2000/svg"
40+
viewBox="0 0 24 24"
41+
fill="none"
42+
stroke-width="2"
43+
class="stroke-white group-aria-expanded:-rotate-180 transition-transform duration-[450ms]"
44+
stroke-linecap="round"
45+
stroke-linejoin="round"
46+
>
47+
<polyline points="6 9 12 15 18 9"></polyline>
48+
</svg>
49+
</ComboboxTrigger>
50+
</ComboboxControl>
51+
<ComboboxPortal>
52+
<ComboboxListbox class="w-full bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
53+
{trainers.map((trainer, index) => (
54+
<ComboboxOption
55+
optionValue={trainer}
56+
key={index}
57+
class="rounded-sm px-2 hover:bg-[#496080] focus:bg-[#496080]"
58+
>
59+
{trainer}
60+
</ComboboxOption>
61+
))}
62+
</ComboboxListbox>
63+
</ComboboxPortal>
64+
</Combobox>
65+
```
66+
</Example01>
67+
68+
## Building blocks
69+
70+
<CodeExample>
71+
```tsx
72+
import { component$ } from '@builder.io/qwik';
73+
import { Combobox, ComboboxLabel, ComboboxControl, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxListbox, ComboboxOption } from '@qwik-ui/headless';
74+
75+
export default component$(() => {
76+
return (
77+
<Combobox>
78+
<ComboboxLabel>Label</ComboboxLabel>
79+
<ComboboxControl>
80+
<ComboboxInput />
81+
<ComboboxTrigger>
82+
Button
83+
</ComboboxTrigger>
84+
</ComboboxControl>
85+
<ComboboxPortal>
86+
<ComboboxListbox>
87+
<ComboboxOption>Option</ComboboxOption>
88+
</ComboboxListbox>
89+
</ComboboxPortal>
90+
</Combobox>
91+
)
92+
})
93+
```
94+
95+
</CodeExample>
96+
97+
## Examples
98+
99+
### EXAMPLE: Frequently Asked Questions
100+
101+
<Example02>```tsx ```</Example02>
102+
103+
## Accessibility
104+
105+
### Keyboard interaction
106+
107+
<KeyboardInteractionTable keyDescriptors={
108+
[
109+
{
110+
keyTitle: 'Tab',
111+
description: 'Moves focus to the next focusable element or option.',
112+
},
113+
{
114+
keyTitle: 'Shift + Tab',
115+
description: 'Moves focus to the previous focusable element or option.',
116+
},
117+
{
118+
keyTitle: 'DownArrow',
119+
description: "Opens the listbox and moves focus to the first option. When focus is on an option, moves focus to the next option. If there isn't one, it will go back to the first option.",
120+
},
121+
{
122+
keyTitle: 'UpArrow',
123+
description: "When focus is on an option, moves focus to the previous option. If there isn't one, it will go back to the last option.",
124+
},
125+
{
126+
keyTitle: 'Enter / Space',
127+
description: `Selects the option when focused. The listbox will close and the selected option becomes the input's value.`,
128+
},
129+
{
130+
keyTitle: 'Escape',
131+
description: 'Closes the listbox.',
132+
},
133+
{
134+
keyTitle: 'Home',
135+
description: 'When the input is focused, the cursor moves to the start of the input value. When focused on any listbox option, focus is moved to the first option.',
136+
},
137+
{
138+
keyTitle: 'End',
139+
description: 'When the input is focused, the cursor moves to the end of the input value. When focused on any listbox option, focus is moved to the last option.',
140+
},
141+
{
142+
keyTitle: 'Delete',
143+
description: 'When text is selected in the input, deletes the selected text.',
144+
},
145+
146+
]
147+
}/>
148+
149+
Adheres to the [Combobox](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) WAI-ARIA design pattern. See the W3C Editable Combobox With List Combobox Example for more information.
150+
151+
## API
152+
153+
By default, the API holds available attributes of both native DOM elements and custom Qwik elements. This is thanks to **QwikIntrinsicElements**. Here are some of the notable API's for this component.
154+
155+
### Combobox (Root)
156+
157+
<APITable
158+
propDescriptors={[
159+
{
160+
name: 'class',
161+
type: 'string',
162+
description: 'CSS classes to apply to the Combobox container.',
163+
},
164+
{
165+
name: 'style',
166+
type: 'string',
167+
description: 'inline CSS styles to apply to the Combobox container.',
168+
},
169+
{
170+
name: 'label',
171+
type: 'string',
172+
description: 'The label to give to the accordion item.',
173+
},
174+
{
175+
name: 'onClick$',
176+
type: 'function',
177+
info: 'PropFunction<() => void>',
178+
description: 'A custom click handler',
179+
},
180+
]}
181+
/>

apps/website/src/routes/docs/headless/menu.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
## Components
1010

1111
- [Accordion](/docs/headless/accordion)
12-
- [Autocomplete](/docs/headless/autocomplete)
12+
- [Combobox](/docs/headless/combobox)
1313
- [Popover](/docs/headless/popover)
1414
- [Select](/docs/headless/select)
1515
- [Tabs](/docs/headless/tabs)

0 commit comments

Comments
 (0)