upp-select
A dropdown select component composed of three sub-components: upp-select-item (the trigger), upp-select-list (the dropdown container), and upp-select-option (individual options). It implements ControlValueAccessor for seamless Angular Reactive Forms integration and can also be used standalone with the Changed output.
When to Use
Use upp-select when the user must pick one value from a list of options. It provides a collapsible dropdown pattern that works well on both desktop and kiosk environments. For free-text entry, use upp-input instead; for multi-line text, use upp-textarea.
Demo
Source Code
- HTML
- TypeScript
- SCSS
<div class="demo-scroll-container">
<upp-scrollable [scrollbar]="'y'">
<div class="demo-content">
<h2>Order Configuration</h2>
<p class="demo-description">Configure shipping and payment using <code>upp-select</code> with FormGroup and standalone modes.</p>
<div class="demo-controls">
<ion-button size="small" (click)="toggleDisabled()">Disabled: {{ isDisabled }}</ion-button>
</div>
<!-- Shipping country (FormGroup) -->
<div class="demo-section" [formGroup]="form">
<h3>Shipping Country</h3>
<div class="demo-field">
<upp-select formControlName="country" [disabled]="isDisabled">
<upp-select-item>
<ion-item lines="none">
<ion-icon name="globe-outline" slot="start"></ion-icon>
<ion-label>{{ selectedCountryLabel }}</ion-label>
</ion-item>
</upp-select-item>
<upp-select-list>
<upp-select-option *ngFor="let country of countries" [value]="country.value">
<ion-item lines="none" button>
<ion-label>{{ country.label }}</ion-label>
</ion-item>
</upp-select-option>
</upp-select-list>
</upp-select>
<span class="demo-label">Selected: {{ form.get('country')?.value }}</span>
</div>
</div>
<!-- Payment method (standalone) -->
<div class="demo-section">
<h3>Payment Method</h3>
<div class="demo-field">
<upp-select [disabled]="isDisabled" (Changed)="onPaymentChanged($event)">
<upp-select-item>
<ion-item lines="none">
<ion-icon name="card-outline" slot="start"></ion-icon>
<ion-label>{{ selectedPaymentLabel }}</ion-label>
</ion-item>
</upp-select-item>
<upp-select-list>
<upp-select-option *ngFor="let method of paymentMethods" [value]="method.value">
<ion-item lines="none" button>
<ion-label>{{ method.label }}</ion-label>
</ion-item>
</upp-select-option>
</upp-select-list>
</upp-select>
<span class="demo-label">Selected: {{ paymentMethod || 'none' }}</span>
</div>
</div>
</div>
</upp-scrollable>
</div>
import { Component, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
@Component({
selector: 'demo-upp-select',
templateUrl: './demo-upp-select.html',
styleUrls: ['../demo-common.scss', './demo-upp-select.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DemoUppSelectComponent implements OnInit {
form!: FormGroup;
paymentMethod: string | null = null;
isDisabled = false;
countries = [
{ value: 'es', label: 'Spain' },
{ value: 'fr', label: 'France' },
{ value: 'de', label: 'Germany' },
{ value: 'it', label: 'Italy' },
{ value: 'pt', label: 'Portugal' },
{ value: 'gb', label: 'United Kingdom' },
];
paymentMethods = [
{ value: 'cash', label: 'Cash' },
{ value: 'card', label: 'Card' },
{ value: 'transfer', label: 'Transfer' },
];
constructor(private change: ChangeDetectorRef) {
}
ngOnInit() {
this.form = new FormGroup({
country: new FormControl('es'),
});
}
get selectedCountryLabel(): string {
const code = this.form.get('country')?.value;
return this.countries.find(c => c.value === code)?.label || 'None';
}
get selectedPaymentLabel(): string {
return this.paymentMethods.find(p => p.value === this.paymentMethod)?.label || 'None';
}
toggleDisabled() {
this.isDisabled = !this.isDisabled;
this.change.markForCheck();
}
onPaymentChanged(value: any) {
this.paymentMethod = value;
this.change.markForCheck();
}
}
:host {
display: block;
height: 100vh;
}
API Reference
UppSelectComponent (upp-select)
The main select component. Uses content projection to compose the trigger (upp-select-item), the list container (upp-select-list), and individual options (upp-select-option).
Inputs
| Property | Type | Default | Description |
|---|---|---|---|
formControlName | string | '' | Name of the reactive form control this select binds to. |
disabled | boolean | false | When true, the select is disabled. Also respects the parent FormGroup disabled state. |
value | any | null | The currently selected value (two-way via ControlValueAccessor). |
Outputs
| Event | Payload | Description |
|---|---|---|
Changed | any | Emitted when the selected value changes. |
Focus | void | Emitted when the select gains focus. |
Content Projection
| Slot | Component | Description |
|---|---|---|
| Trigger | upp-select-item | The clickable element that opens/closes the dropdown. |
| List | upp-select-list | The container that holds the list of options. |
UppSelectItemComponent (upp-select-item)
The trigger element for the dropdown. Clicking it toggles the visibility of the associated upp-select-list.
Outputs
| Event | Payload | Description |
|---|---|---|
Expand | boolean | Emitted when the item is expanded or collapsed. |
UppSelectListComponent (upp-select-list)
The container for upp-select-option elements. It expands/collapses based on the parent upp-select-item state.
Outputs
| Event | Payload | Description |
|---|---|---|
Select | any | Emitted when an option within the list is selected. |
UppSelectOptionComponent (upp-select-option)
An individual option inside a upp-select-list.
Inputs
| Property | Type | Default | Description |
|---|---|---|---|
value | any | null | The value associated with this option. Passed to the parent on selection. |
Outputs
| Event | Payload | Description |
|---|---|---|
Select | any | Emitted when this option is selected. |