diff --git a/projects/core/components/primitive-textfield/primitive-textfield.template.html b/projects/core/components/primitive-textfield/primitive-textfield.template.html
index 7aeb5b48a44b..dd89a83ed2ab 100644
--- a/projects/core/components/primitive-textfield/primitive-textfield.template.html
+++ b/projects/core/components/primitive-textfield/primitive-textfield.template.html
@@ -16,6 +16,7 @@
(tuiAutofilledChange)="onAutofilled($event)"
>
+
+
+ Character
+
+
+
+
+ Food
+
+
+
+
+
diff --git a/projects/demo/src/modules/components/select/examples/11/index.ts b/projects/demo/src/modules/components/select/examples/11/index.ts
new file mode 100644
index 000000000000..894aa62bf8c2
--- /dev/null
+++ b/projects/demo/src/modules/components/select/examples/11/index.ts
@@ -0,0 +1,31 @@
+import {Component} from '@angular/core';
+import {FormControl} from '@angular/forms';
+import {changeDetection} from '@demo/emulate/change-detection';
+import {encapsulation} from '@demo/emulate/encapsulation';
+
+@Component({
+ selector: `tui-select-example-11`,
+ templateUrl: `./index.html`,
+ changeDetection,
+ encapsulation,
+})
+export class TuiSelectExample11 {
+ itemControl = new FormControl();
+ itemGroupControl = new FormControl();
+
+ items = [
+ `Luke Skywalker`,
+ `Leia Organa Solo`,
+ `Darth Vader`,
+ `Han Solo`,
+ `Obi-Wan Kenobi`,
+ `Yoda`,
+ ];
+
+ groupItems = [
+ [`Caesar`, `Greek`, `Apple and Chicken`],
+ [`Broccoli Cheddar`, `Chicken and Rice`, `Chicken Noodle`],
+ ];
+
+ labels = [`Salad`, `Soup`];
+}
diff --git a/projects/demo/src/modules/components/select/select.component.ts b/projects/demo/src/modules/components/select/select.component.ts
index 79b701119cfe..c4444b5cc00e 100644
--- a/projects/demo/src/modules/components/select/select.component.ts
+++ b/projects/demo/src/modules/components/select/select.component.ts
@@ -106,6 +106,11 @@ export class ExampleTuiSelectComponent extends AbstractExampleTuiControl {
HTML: import(`./examples/10/index.html?raw`),
};
+ readonly example11: TuiDocExample = {
+ TypeScript: import(`./examples/11/index.ts?raw`),
+ HTML: import(`./examples/11/index.html?raw`),
+ };
+
readonly items = [new Account(`Ruble`, 500), new Account(`Dollar`, 237)];
readonly valueTemplateVariants = [``, `Template`];
diff --git a/projects/demo/src/modules/components/select/select.module.ts b/projects/demo/src/modules/components/select/select.module.ts
index d9202a40a3b7..41329f081a4f 100644
--- a/projects/demo/src/modules/components/select/select.module.ts
+++ b/projects/demo/src/modules/components/select/select.module.ts
@@ -42,6 +42,7 @@ import {TuiSelectExample8} from './examples/8';
import {TuiSelectExample9} from './examples/9';
import {ExampleMyAccountComponent} from './examples/9/account/my-account.component';
import {TuiSelectExample10} from './examples/10';
+import {TuiSelectExample11} from './examples/11';
import {ExampleTuiSelectComponent} from './select.component';
@NgModule({
@@ -91,6 +92,7 @@ import {ExampleTuiSelectComponent} from './select.component';
TuiSelectExample8,
TuiSelectExample9,
TuiSelectExample10,
+ TuiSelectExample11,
],
exports: [ExampleTuiSelectComponent],
})
diff --git a/projects/demo/src/modules/components/select/select.template.html b/projects/demo/src/modules/components/select/select.template.html
index 7f0d1d6d1f19..bb4e26d441b3 100644
--- a/projects/demo/src/modules/components/select/select.template.html
+++ b/projects/demo/src/modules/components/select/select.template.html
@@ -101,6 +101,21 @@
>
+
+
+
+ You can enable native select on mobile devices by putting
+ select
+ inside with
+ tuiSelect
+ directive as shown below
+
+
+
diff --git a/projects/kit/components/select/index.ts b/projects/kit/components/select/index.ts
index bea9eb96ef59..5fa64673b254 100644
--- a/projects/kit/components/select/index.ts
+++ b/projects/kit/components/select/index.ts
@@ -1,3 +1,6 @@
+export * from './native-select/native-select';
+export * from './native-select/native-select.component';
+export * from './native-select/native-select-group.component';
export * from './select.component';
export * from './select.directive';
export * from './select.module';
diff --git a/projects/kit/components/select/native-select/native-select-group.component.ts b/projects/kit/components/select/native-select/native-select-group.component.ts
new file mode 100644
index 000000000000..fa9bcf9f27a1
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select-group.component.ts
@@ -0,0 +1,42 @@
+import {ChangeDetectionStrategy, Component, Input, TemplateRef} from '@angular/core';
+import {TuiDataListDirective} from '@taiga-ui/core';
+
+import {AbstractTuiNativeSelect} from './native-select';
+
+@Component({
+ selector: `select[tuiSelect][labels]`,
+ templateUrl: `./native-select-group.template.html`,
+ providers: [
+ {
+ provide: TuiDataListDirective,
+ deps: [TuiNativeSelectGroupComponent],
+ useExisting: TuiNativeSelectGroupComponent,
+ },
+ {
+ provide: TemplateRef,
+ deps: [TuiNativeSelectGroupComponent],
+ useFactory: ({datalist}: TuiNativeSelectGroupComponent) => datalist,
+ },
+ {
+ provide: AbstractTuiNativeSelect,
+ useExisting: TuiNativeSelectGroupComponent,
+ },
+ ],
+ host: {
+ '[attr.aria-invalid]': `host.invalid`,
+ '[disabled]': `host.disabled`,
+ '[tabIndex]': `host.focusable ? 0 : -1`,
+ '[readOnly]': `host.readOnly`,
+ '[value]': `host.value`,
+ '(change)': `host.onValueChange($event.target.value)`,
+ },
+ styleUrls: [`./native-select.style.less`],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class TuiNativeSelectGroupComponent extends AbstractTuiNativeSelect {
+ @Input()
+ items: readonly string[][] | null = [];
+
+ @Input()
+ labels: readonly string[] = [];
+}
diff --git a/projects/kit/components/select/native-select/native-select-group.template.html b/projects/kit/components/select/native-select/native-select-group.template.html
new file mode 100644
index 000000000000..7eadd005f1cf
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select-group.template.html
@@ -0,0 +1,16 @@
+
+
diff --git a/projects/kit/components/select/native-select/native-select.component.ts b/projects/kit/components/select/native-select/native-select.component.ts
new file mode 100644
index 000000000000..8c763623d5bd
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select.component.ts
@@ -0,0 +1,39 @@
+import {ChangeDetectionStrategy, Component, Input, TemplateRef} from '@angular/core';
+import {TuiDataListDirective} from '@taiga-ui/core';
+
+import {AbstractTuiNativeSelect} from './native-select';
+
+@Component({
+ selector: `select[tuiSelect]:not([labels])`,
+ templateUrl: `./native-select.template.html`,
+ providers: [
+ {
+ provide: TuiDataListDirective,
+ deps: [TuiNativeSelectComponent],
+ useExisting: TuiNativeSelectComponent,
+ },
+ {
+ provide: TemplateRef,
+ deps: [TuiNativeSelectComponent],
+ useFactory: ({datalist}: TuiNativeSelectComponent) => datalist,
+ },
+ {
+ provide: AbstractTuiNativeSelect,
+ useExisting: TuiNativeSelectComponent,
+ },
+ ],
+ host: {
+ '[attr.aria-invalid]': `host.invalid`,
+ '[disabled]': `host.disabled`,
+ '[tabIndex]': `host.focusable ? 0 : -1`,
+ '[readOnly]': `host.readOnly`,
+ '[value]': `host.value`,
+ '(change)': `host.onValueChange($event.target.value)`,
+ },
+ styleUrls: [`./native-select.style.less`],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class TuiNativeSelectComponent extends AbstractTuiNativeSelect {
+ @Input()
+ items: readonly string[] | null = [];
+}
diff --git a/projects/kit/components/select/native-select/native-select.style.less b/projects/kit/components/select/native-select/native-select.style.less
new file mode 100644
index 000000000000..8ecda8dcf45d
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select.style.less
@@ -0,0 +1,6 @@
+@import 'taiga-ui-local';
+
+:host {
+ .fullsize();
+ opacity: 0;
+}
diff --git a/projects/kit/components/select/native-select/native-select.template.html b/projects/kit/components/select/native-select/native-select.template.html
new file mode 100644
index 000000000000..c0bb2efebc5b
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select.template.html
@@ -0,0 +1,10 @@
+
+
diff --git a/projects/kit/components/select/native-select/native-select.ts b/projects/kit/components/select/native-select/native-select.ts
new file mode 100644
index 000000000000..1dba2639b95e
--- /dev/null
+++ b/projects/kit/components/select/native-select/native-select.ts
@@ -0,0 +1,30 @@
+import {
+ Directive,
+ ElementRef,
+ HostBinding,
+ Inject,
+ TemplateRef,
+ ViewChild,
+} from '@angular/core';
+import {TuiIdService} from '@taiga-ui/cdk';
+import {TUI_TEXTFIELD_HOST, TuiDataListDirective, TuiTextfieldHost} from '@taiga-ui/core';
+
+@Directive()
+export abstract class AbstractTuiNativeSelect {
+ @ViewChild(TuiDataListDirective, {read: TemplateRef, static: true})
+ readonly datalist: TemplateRef | null = null;
+
+ constructor(
+ @Inject(TUI_TEXTFIELD_HOST) readonly host: TuiTextfieldHost,
+ @Inject(ElementRef) private readonly elementRef: ElementRef,
+ @Inject(TuiIdService)
+ private readonly idService: TuiIdService,
+ ) {
+ this.host.process(this.elementRef.nativeElement);
+ }
+
+ @HostBinding(`id`)
+ get id(): string {
+ return this.elementRef.nativeElement.id || this.idService.generate();
+ }
+}
diff --git a/projects/kit/components/select/select.component.ts b/projects/kit/components/select/select.component.ts
index af190316ff8b..88d9f7c044a1 100644
--- a/projects/kit/components/select/select.component.ts
+++ b/projects/kit/components/select/select.component.ts
@@ -13,6 +13,7 @@ import {
import {NgControl} from '@angular/forms';
import {
AbstractTuiNullableControl,
+ TUI_IS_MOBILE,
TuiActiveZoneDirective,
tuiAsControl,
tuiAsFocusableItemAccessor,
@@ -41,6 +42,7 @@ import {FIXED_DROPDOWN_CONTROLLER_PROVIDER} from '@taiga-ui/kit/providers';
import {TUI_ITEMS_HANDLERS, TuiItemsHandlers} from '@taiga-ui/kit/tokens';
import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus';
+import {AbstractTuiNativeSelect} from './native-select/native-select';
import {TUI_SELECT_OPTIONS, TuiSelectOptions} from './select-options';
@Component({
@@ -66,6 +68,9 @@ export class TuiSelectComponent
@ViewChild(TuiHostedDropdownComponent)
private readonly hostedDropdown?: TuiHostedDropdownComponent;
+ @ContentChild(AbstractTuiNativeSelect, {static: true})
+ private readonly nativeSelect?: AbstractTuiNativeSelect;
+
@Input()
@tuiDefaultProp()
stringify: TuiItemsHandlers['stringify'] = this.itemsHandlers.stringify;
@@ -98,6 +103,8 @@ export class TuiSelectComponent
private readonly itemsHandlers: TuiItemsHandlers,
@Inject(TUI_SELECT_OPTIONS)
private readonly options: TuiSelectOptions,
+ @Inject(TUI_IS_MOBILE)
+ readonly isMobile: boolean,
) {
super(control, changeDetectorRef);
}
@@ -119,6 +126,10 @@ export class TuiSelectComponent
);
}
+ get nativeDropdownMode(): boolean {
+ return !!this.nativeSelect && this.isMobile;
+ }
+
get computedValue(): string {
return this.value === null ? `` : this.stringify(this.value) || ` `;
}
@@ -127,9 +138,11 @@ export class TuiSelectComponent
return this.valueContent || this.computedValue;
}
- onValueChange(value: string): void {
+ onValueChange(value: T): void {
if (!value) {
this.updateValue(null);
+ } else {
+ this.updateValue(value || null);
}
}
diff --git a/projects/kit/components/select/select.module.ts b/projects/kit/components/select/select.module.ts
index 2a90d7aecb53..0abc1b9a7ed9 100644
--- a/projects/kit/components/select/select.module.ts
+++ b/projects/kit/components/select/select.module.ts
@@ -2,15 +2,19 @@ import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {TuiActiveZoneModule} from '@taiga-ui/cdk';
import {
+ TuiDataListModule,
TuiHostedDropdownModule,
TuiPrimitiveTextfieldModule,
TuiTextfieldComponent,
TuiTextfieldControllerModule,
} from '@taiga-ui/core';
import {TuiArrowModule} from '@taiga-ui/kit/components/arrow';
+import {TuiDataListWrapperModule} from '@taiga-ui/kit/components/data-list-wrapper';
import {TuiSelectOptionModule} from '@taiga-ui/kit/components/select-option';
import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus';
+import {TuiNativeSelectComponent} from './native-select/native-select.component';
+import {TuiNativeSelectGroupComponent} from './native-select/native-select-group.component';
import {TuiSelectComponent} from './select.component';
import {TuiSelectDirective} from './select.directive';
@@ -24,8 +28,21 @@ import {TuiSelectDirective} from './select.directive';
TuiSelectOptionModule,
TuiArrowModule,
TuiTextfieldControllerModule,
+ TuiDataListWrapperModule,
+ TuiDataListModule,
+ ],
+ declarations: [
+ TuiSelectComponent,
+ TuiSelectDirective,
+ TuiNativeSelectComponent,
+ TuiNativeSelectGroupComponent,
+ ],
+ exports: [
+ TuiSelectComponent,
+ TuiSelectDirective,
+ TuiTextfieldComponent,
+ TuiNativeSelectComponent,
+ TuiNativeSelectGroupComponent,
],
- declarations: [TuiSelectComponent, TuiSelectDirective],
- exports: [TuiSelectComponent, TuiSelectDirective, TuiTextfieldComponent],
})
export class TuiSelectModule {}
diff --git a/projects/kit/components/select/select.template.html b/projects/kit/components/select/select.template.html
index 74ba479fdd33..ad4555dfb94b 100644
--- a/projects/kit/components/select/select.template.html
+++ b/projects/kit/components/select/select.template.html
@@ -1,6 +1,6 @@
@@ -18,7 +18,7 @@
[disabled]="computedDisabled"
[focusable]="computedFocusable"
[value]="computedValue"
- (valueChange)="onValueChange($event)"
+ (valueChange)="onValueChange($any($event))"
(keydown.delete.prevent)="onKeyDownDelete()"
(keydown.backspace.prevent)="onKeyDownDelete()"
>
@@ -27,6 +27,21 @@
select="input"
ngProjectAs="input"
>
+
+
+
+
+
+
+
+
+