Select

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

Loading...
 import { Component } from '@angular/core';
 
import {
    RdxSelectComponent,
    RdxSelectContentDirective,
    RdxSelectGroupDirective,
    RdxSelectIconDirective,
    RdxSelectItemDirective,
    RdxSelectItemIndicatorDirective,
    RdxSelectLabelDirective,
    RdxSelectSeparatorDirective,
    RdxSelectTriggerDirective,
    RdxSelectValueDirective
} from '@radix-ng/primitives/select';
import { Check, ChevronDown, LucideAngularModule } from 'lucide-angular';
 
@Component({
    selector: 'radix-select-demo',
    standalone: true,
    imports: [
        RdxSelectComponent,
        RdxSelectSeparatorDirective,
        RdxSelectLabelDirective,
        RdxSelectItemIndicatorDirective,
        RdxSelectItemDirective,
        RdxSelectGroupDirective,
        RdxSelectContentDirective,
        RdxSelectTriggerDirective,
        RdxSelectValueDirective,
        RdxSelectIconDirective,
        LucideAngularModule
    ],
    template: `
        <span rdxSelect>
            <button class="SelectTrigger" rdxSelectTrigger>
                <span rdxSelectValue placeholder="Select a fruit…"></span>
                <lucide-icon class="SelectIcon" [img]="LucideChevronDownIcon" size="16" rdxSelectIcon />
            </button>
            <div class="SelectContent SelectViewport" rdxSelectContent>
                @for (group of foodGroups; track group; let last = $last) {
                    <div class="SelectGroup" rdxSelectGroup>
                        <div class="SelectLabel" rdxSelectLabel>{{ group.label }}</div>
                        @for (food of group.foods; track food) {
                            <div class="SelectItem" [value]="food.value" [disabled]="food.disabled" rdxSelectItem>
                                <lucide-icon
                                    class="SelectItemIndicator"
                                    [img]="LucideCheckIcon"
                                    rdxSelectItemIndicator
                                    size="16"
                                />
                                {{ food.label }}
                            </div>
                        }
                    </div>
                    @if (!last) {
                        <div class="SelectSeparator" rdxSelectSeparator></div>
                    }
                }
            </div>
        </span>
    `,
    styleUrl: 'select-demo.css'
})
export class SelectDemoComponent {
    readonly LucideChevronDownIcon = ChevronDown;
    readonly LucideCheckIcon = Check;
 
    readonly foodGroups: FoodArray = [
        {
            label: 'Fruits',
            foods: [
                { value: 'apple', label: 'Apple' },
                { value: 'banana', label: 'Banana' },
                { value: 'blueberry', label: 'Blueberry' },
                { value: 'grapes', label: 'Grapes' },
                { value: 'pineapple', label: 'Pineapple' }
            ]
        },
        {
            label: 'Vegetables',
            foods: [
                { value: 'aubergine', label: 'Aubergine' },
                { value: 'broccoli', label: 'Broccoli' },
                { value: 'carrot', label: 'Carrot', disabled: true },
                { value: 'courgette', label: 'Courgette' },
                { value: 'leek', label: 'Leek' }
            ]
        },
        {
            label: 'Meat',
            foods: [
                { value: 'beef', label: 'Beef' },
                { value: 'beef-with-sauce', label: 'Beef with sauce' },
                { value: 'chicken', label: 'Chicken' },
                { value: 'lamb', label: 'Lamb' },
                { value: 'pork', label: 'Pork' }
            ]
        },
        {
            foods: [
                { value: 'candies', label: 'Candies' },
                { value: 'chocolates', label: 'Chocolates' }
            ]
        }
    ];
    item: any;
}
 
type FoodItem = {
    value: string;
    label: string;
    disabled?: boolean;
};
 
type Category = {
    label?: string;
    foods: FoodItem[];
};
 
type FoodArray = Category[];
  
 /* reset */
:host {
    button {
        all: unset;
    }
}
 
.SelectTrigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    padding: 0 15px;
    font-size: 13px;
    line-height: 1;
    height: 35px;
    gap: 5px;
    background-color: white;
    color: var(--violet-11);
    box-shadow: 0 2px 10px var(--black-a7);
}
 
.SelectTrigger:hover {
    background-color: var(--mauve-3);
}
 
.SelectTrigger:focus {
    box-shadow: 0 0 0 2px black;
}
 
.SelectTrigger[data-placeholder] {
    color: var(--violet-9);
}
 
.SelectIcon {
    color: Var(--violet-11);
}
 
.SelectContent {
    overflow: hidden;
    background-color: white;
    border-radius: 6px;
    box-shadow:
        0px 10px 38px -10px rgba(22, 23, 24, 0.35),
        0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}
 
.SelectViewport {
    padding: 5px;
}
 
.SelectItem {
    font-size: 13px;
    line-height: 1;
    color: var(--violet-11);
    border-radius: 3px;
    display: flex;
    align-items: center;
    height: 25px;
    padding: 0 35px 0 25px;
    position: relative;
    user-select: none;
}
 
.SelectItem[data-disabled] {
    color: var(--mauve-8);
    pointer-events: none;
}
 
.SelectItem[data-highlighted] {
    outline: none;
    background-color: var(--violet-9);
    color: var(--violet-1);
}
 
.SelectLabel {
    padding: 0 25px;
    font-size: 12px;
    line-height: 25px;
    color: var(--mauve-11);
}
 
.SelectSeparator {
    height: 1px;
    background-color: var(--violet-6);
    margin: 5px;
}
 
.SelectItemIndicator {
    position: absolute;
    left: 0;
    width: 25px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
 
.SelectScrollButton {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 25px;
    background-color: white;
    color: var(--violet-11);
    cursor: default;
} 

Features

  • Can be controlled or uncontrolled.
  • Supports items, labels, groups of items.
  • Focus is fully managed.
  • Full keyboard navigation.

Anatomy

 <div rdxSelectRoot>
    <div rdxSelectContent>
        <div rdxSelectItem></div>
    </div>
</div> 

API Reference

Root