Edit Profile

Dark Mode

Copy config

Copy and paste the following code into your global.css file to apply the styles.

WARNING: This component is in
Draft
status. This means that it is still in development and may have bugs or missing features. It is not intended to be used in production. You may use it for testing purposes.

Select

Displays a list of options for the user to pick from — triggered by a button.

Installation

Run the following cli command or copy/paste the component code into your project

qwik-ui add select
import { PropsOf, Slot, component$ } from '@builder.io/qwik';
import { Select as HeadlessSelect } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
 
const Root = (props: PropsOf<typeof HeadlessSelect.Root>) => (
  <HeadlessSelect.Root
    {...props}
    selectItemComponent={Item}
    selectItemLabelComponent={ItemLabel}
    selectLabelComponent={Label}
  />
);
 
const Label = component$<PropsOf<typeof HeadlessSelect.Label>>(({ ...props }) => {
  return (
    <>
      <HeadlessSelect.Label
        {...props}
        class={cn('px-2 py-1.5 text-sm font-semibold', props.class)}
      >
        <Slot />
      </HeadlessSelect.Label>
    </>
  );
});
 
const Trigger = component$<PropsOf<typeof HeadlessSelect.Trigger>>(({ ...props }) => {
  return (
    <>
      <HeadlessSelect.Trigger
        {...props}
        class={cn(
          'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
          props.class,
        )}
      >
        <Slot />
        <LuChevronDown class="h-4 w-4 opacity-50" />
      </HeadlessSelect.Trigger>
    </>
  );
});
 
const DisplayValue = HeadlessSelect.DisplayValue;
 
const Popover = component$<PropsOf<typeof HeadlessSelect.Popover>>(({ ...props }) => {
  return (
    <>
      <HeadlessSelect.Popover
        {...props}
        class={cn(
          'w-full max-w-[15rem] data-[open]:animate-in data-[closing]:animate-out data-[closing]:fade-out-0 data-[open]:fade-in-0 data-[closing]:zoom-out-95 data-[open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
          // 'overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md',
          props.class,
        )}
      >
        <Slot />
      </HeadlessSelect.Popover>
    </>
  );
});
 
type ListboxProps = PropsOf<typeof HeadlessSelect.Listbox>;
const Listbox = component$<ListboxProps>(({ ...props }) => {
  return (
    <>
      <HeadlessSelect.Listbox
        {...props}
        class={cn(
          'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
          props.class,
        )}
      >
        <Slot />
      </HeadlessSelect.Listbox>
    </>
  );
});
 
const Group = HeadlessSelect.Group;
 
const GroupLabel = HeadlessSelect.GroupLabel;
 
const Item = component$<PropsOf<typeof HeadlessSelect.Item>>(({ ...props }) => {
  return (
    <HeadlessSelect.Item
      {...props}
      class={cn(
        'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
        'data-[highlighted]:border-base data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',
        props.class,
      )}
    >
      <Slot />
    </HeadlessSelect.Item>
  );
});
 
const ItemIndicator = component$<PropsOf<typeof HeadlessSelect.ItemIndicator>>(
  ({ ...props }) => {
    return (
      <span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
        <HeadlessSelect.ItemIndicator {...props}>
          <LuCheck class="h-4 w-4" />
        </HeadlessSelect.ItemIndicator>
      </span>
    );
  },
);
 
const ItemLabel = component$<PropsOf<typeof HeadlessSelect.ItemLabel>>(({ ...props }) => {
  return (
    <HeadlessSelect.ItemLabel {...props}>
      <Slot />
    </HeadlessSelect.ItemLabel>
  );
});
 
export const Select = {
  Root,
  Label,
  Trigger,
  DisplayValue,
  Popover,
  Listbox,
  Group,
  GroupLabel,
  Item,
  ItemIndicator,
  ItemLabel,
};