No Preview

Sorry, but you either have no stories or none are selected somehow.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

The component failed to render properly, likely due to a configuration issue in Storybook. Here are some common causes and how you can address them:

  1. Missing Context/Providers: You can use decorators to supply specific contexts or providers, which are sometimes necessary for components to render correctly. For detailed instructions on using decorators, please visit the Decorators documentation.
  2. Misconfigured Webpack or Vite: Verify that Storybook picks up all necessary settings for loaders, plugins, and other relevant parameters. You can find step-by-step guides for configuring Webpack or Vite with Storybook.
  3. Missing Environment Variables: Your Storybook may require specific environment variables to function as intended. You can set up custom environment variables as outlined in the Environment Variables documentation.

A custom select for NgBootstrap that uses the ngbDropdown.

This component is deprecated

It will be removed in the next major version.

Make sure the @ng-bootstrap/ng-bootstrap package is already present in your project or follow ng-bootstrap installation guidelines.

To import all ng-bootstrap components:

import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; @NgModule({ imports: [NgbModule], }) export class YourAppModule { }

To import only this component:

import {undefined} from '@ng-bootstrap/ng-bootstrap'; @NgModule({ imports: [undefined], }) export class YourAppModule { }

Make sure the @swisspost/design-system-styles package is already present in your project or follow the installation guidelines.

To import all Design System styles:

@use '@swisspost/design-system-styles/index.scss';

To import only the styles required for this component:

@use '@swisspost/design-system-styles/basics.scss'; @use '@swisspost/design-system-styles/components/forms.scss'; @use '@swisspost/design-system-styles/components/form-select.scss'; // required if you use floating-labels @use '@swisspost/design-system-styles/components/floating-label.scss';
Basic example
<div ngbDropdown> <input [ngModel]="selectedOption?.value" name="meansOfTransport" type="hidden" /> <button #toggle aria-haspopup="listbox" (keydown)="setFocus($event)" id="customSelectButton" class="form-select text-start no-toggle-arrow" ngbDropdownToggle type="button" > <span [class.visually-hidden]="selectedOption">Default custom-select</span> <span *ngIf="selectedOption" aria-hidden="true">{{ selectedOption.label }}</span> </button> <div aria-labelledby="customSelectButton" class="w-100 mw-100" ngbDropdownMenu role="listbox"> <button (click)="toggle.focus()" (focus)="selectedOption = option" *ngFor="let option of options" [attr.aria-selected]="selectedOption?.value === option.value" [class.active]="selectedOption?.value === option.value" class="d-flex align-items-center" ngbDropdownItem role="option" type="button" #option > <em aria-hidden="true" class="pi me-small-regular" [class]="'pi-' + option.icon"></em> <span>{{ option.label }}</span> </button> </div> </div>
import { Component, ElementRef, QueryList, ViewChildren } from '@angular/core'; interface IOption { label: string; value: string; icon: number; } @Component({ selector: 'app-custom-select-demo', templateUrl: './custom-select-demo.component.html', }) export class CustomSelectDemoComponent { @ViewChildren('option', { read: ElementRef }) private optionList: QueryList<ElementRef>; public options: IOption[]; public selectedOption: IOption; constructor() { this.options = [ { label: 'One', value: '1', icon: 3126, }, { label: 'Two', value: '2', icon: 3116, }, { label: 'Three', value: '3', icon: 3107, }, ]; } public setFocus(event: KeyboardEvent) { const activeOptionIndex = Array.from(this.optionList).findIndex(option => { return option.nativeElement.classList.contains('active'); }); switch (event.code) { case 'Space': case 'Enter': const currentOption = this.optionList.get(activeOptionIndex) || this.optionList.get(0); setTimeout(() => currentOption.nativeElement.focus(), 100); break; case 'ArrowUp': const previousOption = this.optionList.get(activeOptionIndex + 1) || this.optionList.get(0); setTimeout(() => previousOption.nativeElement.focus()); break; case 'ArrowDown': const nextOption = this.optionList.get(activeOptionIndex + 1) || this.optionList.get(0); setTimeout(() => nextOption.nativeElement.focus()); break; } } }
Floating example
<div class="form-floating" ngbDropdown> <input [ngModel]="selectedOption?.value" name="meansOfTransport" type="hidden" /> <button #toggle aria-haspopup="listbox" (keydown)="setFocus($event)" aria-labelledby="customSelectLabel" class="form-select custom-select text-start no-toggle-arrow" ngbDropdownToggle type="button" > <span *ngIf="selectedOption" aria-hidden="true">{{ selectedOption.label }}</span> </button> <label class="form-label" id="customSelectLabel"> Floatinglabel custom-select {{ infoText }} </label> <div aria-labelledby="customSelectLabel" class="w-100 mw-100" ngbDropdownMenu role="listbox"> <button (click)="toggle.focus()" (focus)="selectedOption = option" *ngFor="let option of options" [attr.aria-selected]="selectedOption?.value === option.value" [class.active]="selectedOption?.value === option.value" class="d-flex align-items-center" ngbDropdownItem role="option" type="button" #option > <em aria-hidden="true" class="pi me-small-regular" [class]="'pi-' + option.icon"></em> <span>{{ option.label }}</span> </button> </div> </div>
import { Component, ElementRef, QueryList, ViewChildren, OnInit, Input } from '@angular/core'; interface IOption { label: string; value: string; icon: number; } @Component({ selector: 'app-custom-select-floating-demo', templateUrl: './custom-select-floating-demo.component.html', }) export class CustomSelectFloatingDemoComponent implements OnInit { @ViewChildren('option', { read: ElementRef }) private optionList: QueryList<ElementRef>; @Input() public noSelected: boolean = false; public infoText: string = ''; ngOnInit() { if (!this.noSelected) this.selectedOption = this.options[0]; this.infoText = this.noSelected ? `(no selected)` : ''; } public options: IOption[]; public selectedOption: IOption; constructor() { this.options = [ { label: 'One', value: '1', icon: 3126, }, { label: 'Two', value: '2', icon: 3116, }, { label: 'Three', value: '3', icon: 3107, }, ]; } public setFocus(event: KeyboardEvent) { const activeOptionIndex = Array.from(this.optionList).findIndex(option => { return option.nativeElement.classList.contains('active'); }); switch (event.code) { case 'Space': case 'Enter': const currentOption = this.optionList.get(activeOptionIndex) || this.optionList.get(0); setTimeout(() => currentOption.nativeElement.focus(), 100); break; case 'ArrowUp': const previousOption = this.optionList.get(activeOptionIndex + 1) || this.optionList.get(0); setTimeout(() => previousOption.nativeElement.focus()); break; case 'ArrowDown': const nextOption = this.optionList.get(activeOptionIndex + 1) || this.optionList.get(0); setTimeout(() => nextOption.nativeElement.focus()); break; } } }