Skip to content
Draft
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
5 changes: 3 additions & 2 deletions docs/src/app/(docs)/react/components/combobox/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import { DemoComboboxHero } from './demos/hero';

## Usage guidelines

- **Combobox is a filterable Select**: Use Combobox when the input is restricted to a set of predefined selectable items, similar to [Select](/react/components/select) but whose items are filterable using an input. Prefer using Combobox over Select when the number of items is sufficiently large to warrant filtering.
- **Combobox is input-first**: The input is the control. The query persists while the user edits it, which suits asynchronous or external data, virtualised lists, autocomplete modes, and richer multiple-selection and chip composition.
- **Prefer Select for a trigger-first control**: [Select](/react/components/select) is a form control with a trigger, and its `filter` prop adds a transient finder inside the popup. Choose Select for a fixed set of discrete choices in a modest, fully mounted list. Choose Combobox when the list is large, remote, or virtualised.
- **Avoid for simple search widgets**: Combobox does not allow free-form text input. For search widgets, consider using [Autocomplete](/react/components/autocomplete) instead.
- **Avoid when not rendering an input**: Use [Select](/react/components/select) instead of Combobox if no input is being rendered, which includes accessibility features specific to a listbox without an input.
- **Avoid for actions**: Combobox selects a value. To let users find and run a command, use a filterable [Menu](/react/components/menu) instead.
- **Form controls must have an accessible name**: If `<Combobox.Input>` is the form control, label it with a native `<label>` or `<Field.Label>`, or provide an `aria-label` when no visible label is rendered. `<Combobox.Label>` labels `<Combobox.Trigger>` and is intended for the [input-inside-popup](#input-inside-popup) pattern, where the trigger is the form control. See the [forms guide](/react/handbook/forms).

## Anatomy
Expand Down
4 changes: 2 additions & 2 deletions docs/src/app/(docs)/react/components/context-menu/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ Renders a `<div>` element.

| Prop | Type | Default | Description |
| :----------- | :--------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| label | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. |
| label | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation,&#xA;and when filtering. |
| onClick | `((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)` | - | The click handler for the menu item. |
| closeOnClick | `boolean` | `true` | Whether to close the menu when the item is clicked. |
| nativeButton | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `true` if the rendered element is a native button. |
Expand Down Expand Up @@ -586,7 +586,7 @@ Renders a `<div>` element.

| Prop | Type | Default | Description |
| :----------- | :------------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| label | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation. |
| label | `string` | - | Overrides the text label to use when the item is matched during keyboard text navigation,&#xA;and when filtering. |
| onClick | `((event: BaseUIEvent<React.MouseEvent<HTMLDivElement, MouseEvent>>) => void)` | - | - |
| nativeButton | `boolean` | `false` | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `true` if the rendered element is a native button. |
| disabled | `boolean` | `false` | Whether the component should ignore user interaction. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
.Trigger {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
height: 2rem;
padding: 0 0.5rem 0 0.75rem;
margin: 0;
border: 1px solid oklch(14.5% 0 0deg);
border-radius: 0;
outline: 0;
background-color: white;
color: oklch(14.5% 0 0deg);
font-family: inherit;
font-size: 0.875rem;
font-weight: 400;
line-height: 1;
white-space: nowrap;
-webkit-user-select: none;
user-select: none;

@media (prefers-color-scheme: dark) {
border-color: white;
background-color: oklch(14.5% 0 0deg);
color: white;
}

@media (hover: hover) {
&:hover:not([data-disabled]) {
background-color: oklch(97% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: oklch(26.9% 0 0deg);
}
}
}

&:active:not([data-disabled]) {
background-color: oklch(92.2% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: oklch(37.1% 0 0deg);
}
}

&[data-pressed] {
background-color: oklch(97% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: oklch(26.9% 0 0deg);
}
}

&[data-disabled] {
border-color: oklch(55.6% 0 0deg);
color: oklch(55.6% 0 0deg);

@media (prefers-color-scheme: dark) {
border-color: oklch(70.8% 0 0deg);
color: oklch(70.8% 0 0deg);
}
}

&:focus-visible {
outline: 2px solid oklch(14.5% 0 0deg);
outline-offset: -1px;

@media (prefers-color-scheme: dark) {
outline-color: white;
}
}
}

.Positioner {
outline: 0;
}

.Popup {
box-sizing: border-box;
min-width: max(12rem, var(--anchor-width));
overflow: hidden;
border: 1px solid oklch(14.5% 0 0deg);
border-radius: 0;
outline: 0;
background-color: white;
color: oklch(14.5% 0 0deg);
box-shadow: 0.25rem 0.25rem 0 rgb(0 0 0 / 12%);
transform-origin: var(--transform-origin);
transition:
transform 100ms ease-out,
opacity 100ms ease-out;

@media (prefers-color-scheme: dark) {
border-color: white;
background-color: oklch(14.5% 0 0deg);
color: white;
box-shadow: none;
}

&[data-starting-style],
&[data-ending-style] {
opacity: 0;
transform: scale(0.98);
}
}

.InputContainer {
display: flex;
align-items: center;
border-bottom: 1px solid oklch(87% 0 0deg);

@media (prefers-color-scheme: dark) {
border-color: oklch(37.1% 0 0deg);
}

&:has(.Input[data-focus-visible]) {
border-color: oklch(14.5% 0 0deg);
box-shadow: inset 0 0 0 1px oklch(14.5% 0 0deg);

@media (prefers-color-scheme: dark) {
border-color: white;
box-shadow: inset 0 0 0 1px white;
}
}
}

.Input {
flex: 1;
width: 0;
min-height: 2rem;
padding: 0 0.625rem;
border: 0;
outline: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 0.875rem;
line-height: 1;

&::placeholder {
color: oklch(55.6% 0 0deg);

@media (prefers-color-scheme: dark) {
color: oklch(70.8% 0 0deg);
}
}
}

.Clear {
display: flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
border: 0;
background: transparent;
color: inherit;
}

.List {
max-height: min(16rem, var(--available-height));
padding-block: 0.25rem;
overflow-y: auto;
scroll-padding-block: 0.25rem;

&:empty {
padding-block: 0;
}
}

.Item,
.SubmenuTrigger {
outline: 0;
cursor: default;
-webkit-user-select: none;
user-select: none;
padding-block: 0.5rem;
padding-left: 1rem;
padding-right: 2rem;
display: flex;
font-size: 0.875rem;
line-height: 1rem;

&[data-highlighted] {
z-index: 0;
position: relative;
color: white;

@media (prefers-color-scheme: dark) {
color: oklch(14.5% 0 0deg);
}
}

&[data-highlighted]::before {
content: '';
z-index: -1;
position: absolute;
inset-block: 0;
inset-inline: 0.25rem;
background-color: oklch(14.5% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: white;
}
}
}

.SubmenuTrigger {
align-items: center;
justify-content: space-between;
gap: 1rem;
padding-right: 0.5rem;

&[data-popup-open] {
z-index: 0;
position: relative;
}

&[data-popup-open]::before {
content: '';
z-index: -1;
position: absolute;
inset-block: 0;
inset-inline: 0.25rem;
background-color: oklch(97% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: oklch(26.9% 0 0deg);
}
}

&[data-highlighted][data-popup-open]::before {
background-color: oklch(14.5% 0 0deg);

@media (prefers-color-scheme: dark) {
background-color: white;
}
}
}

.Empty {
padding: 0.75rem;
color: oklch(55.6% 0 0deg);
font-size: 0.875rem;
line-height: 1.25rem;

@media (prefers-color-scheme: dark) {
color: oklch(70.8% 0 0deg);
}
}
Loading
Loading