The Select component provides a searchable dropdown for selecting a single option from a list with support for custom rendering and async data.
Basic usage
<flx-select
label="Country"
placeholder="Select a country"
[(ngModel)]="selectedCountry"
[options]="countries">
</flx-select>
Properties
Label text displayed above the select
Placeholder text when no option is selected
Array of options to display. Each option should have value and label properties
Marks the field as required
error
boolean | string
default:"false"
Shows error state. Pass a string to display error message
Enables search/filter functionality
Shows clear button when option is selected
Helper text displayed below the select
Events
Emitted when the selected value changes
Emitted when user types in search box
Examples
Basic select
With search
Async loading
Custom option template
Reactive forms
<flx-select
label="Status"
placeholder="Select status"
[(ngModel)]="status"
[options]="statusOptions">
</flx-select>
export class StatusSelect {
status = 'active';
statusOptions = [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' },
{ value: 'archived', label: 'Archived' }
];
}
<flx-select
label="City"
placeholder="Search for a city"
[(ngModel)]="selectedCity"
[options]="cities"
[searchable]="true"
[clearable]="true">
</flx-select>
export class CitySelect {
selectedCity: string;
cities = [
{ value: 'ny', label: 'New York' },
{ value: 'la', label: 'Los Angeles' },
{ value: 'chicago', label: 'Chicago' },
{ value: 'houston', label: 'Houston' },
// ... more cities
];
}
<flx-select
label="User"
placeholder="Search users"
[(ngModel)]="selectedUser"
[options]="users"
[loading]="isLoading"
[searchable]="true"
(search)="searchUsers($event)">
</flx-select>
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
export class UserSelect implements OnInit {
selectedUser: string;
users: SelectOption[] = [];
isLoading = false;
private searchSubject = new Subject<string>();
ngOnInit() {
this.searchSubject.pipe(
debounceTime(300),
distinctUntilChanged()
).subscribe(query => {
this.loadUsers(query);
});
}
searchUsers(query: string) {
this.searchSubject.next(query);
}
async loadUsers(query: string) {
this.isLoading = true;
const results = await this.userService.search(query);
this.users = results.map(user => ({
value: user.id,
label: user.name
}));
this.isLoading = false;
}
}
<flx-select
label="Team member"
[(ngModel)]="selectedMember"
[options]="members">
<ng-template #optionTemplate let-option>
<div class="member-option">
<img [src]="option.avatar" [alt]="option.label" />
<div>
<div class="name">{{ option.label }}</div>
<div class="role">{{ option.role }}</div>
</div>
</div>
</ng-template>
</flx-select>
export class MemberSelect {
selectedMember: string;
members = [
{
value: '1',
label: 'John Doe',
role: 'Developer',
avatar: '/avatars/john.jpg'
},
{
value: '2',
label: 'Jane Smith',
role: 'Designer',
avatar: '/avatars/jane.jpg'
}
];
}
<form [formGroup]="profileForm">
<flx-select
label="Department"
formControlName="department"
[options]="departments"
[error]="departmentControl.invalid && departmentControl.touched"
helperText="Select your department">
</flx-select>
</form>
import { FormBuilder, Validators } from '@angular/forms';
export class ProfileForm {
profileForm = this.fb.group({
department: ['', Validators.required]
});
departments = [
{ value: 'eng', label: 'Engineering' },
{ value: 'design', label: 'Design' },
{ value: 'marketing', label: 'Marketing' },
{ value: 'sales', label: 'Sales' }
];
get departmentControl() { return this.profileForm.get('department')!; }
constructor(private fb: FormBuilder) {}
}
Styling
flx-select {
--flx-select-height: 40px;
--flx-select-border-radius: 4px;
--flx-select-border-color: #d1d5db;
--flx-select-focus-border-color: #3b82f6;
--flx-select-error-border-color: #ef4444;
--flx-select-background: #ffffff;
--flx-select-dropdown-max-height: 300px;
--flx-select-option-padding: 8px 12px;
--flx-select-option-hover-background: #f3f4f6;
--flx-select-option-selected-background: #dbeafe;
}
Accessibility
The Select component is fully accessible:
- Keyboard navigation (Arrow keys, Enter, Escape)
role="combobox" with proper ARIA attributes
aria-expanded, aria-activedescendant for dropdown state
- Screen reader announcements for selection changes
- Focus management
Best practices
- Use searchable select for lists with more than 10 options
- Provide clear labels and placeholder text
- Enable clearable for optional fields
- Use async loading for large datasets
- Group related options when appropriate
- Consider MultiSelect for multiple selections