GUILD OF GLEKS UIv21.4.4

gog-select

Select

A dropdown select with five sizes, disabled options, placement control, a body-portaled panel, and full ControlValueAccessor support. Once open, Arrow Up/Down move between options, Home/End jump to the first/last, and Escape closes.

Overview

Import the component and drop it into a template.

typescript
import { SelectComponent } from '@guildofgleks/ui';

@Component({
  // ...
  imports: [SelectComponent],
})

Basic usage — a labeled field bound with [(value)]:

<gog-select label="Framework" [options]="frameworks" [(value)]="framework" />

Examples

Sizes

Five size steps, from xsm to slg.

@for (sizeOption of sizes; track sizeOption) {
  <gog-select [label]="'Size: ' + sizeOption" [size]="sizeOption" [options]="frameworks" [(value)]="sizeDemoValue" />
}

Disabled option & disabled field

A single option can be marked disabled without disabling the whole field, or the trigger itself can be disabled with [disabled]="true". The last field shows an error computed entirely by the page — gog-select just renders whatever errorMessage it's given, for as long as it's non-empty.

Please pick a plan.
<gog-select label="Disabled" [options]="frameworks" value="angular" [disabled]="true" />

<gog-select label="Plan (one option disabled)" [options]="plansWithDisabled" [(value)]="plan" />

<gog-select
  label="Required plan"
  placeholder="Choose a plan..."
  [options]="plansWithDisabled"
  [errorMessage]="requiredValue() === null ? 'Please pick a plan.' : ''"
  [(value)]="requiredValue"
/>

Reactive Forms — automatic error timing

With errorDisplay="auto" and a [formControl], the field decides for itself when to show the error — once the control has been touched and is invalid — instead of the page computing that timing. Click the field, then click away without choosing anything.

<gog-select
  label="Billing cycle"
  placeholder="Choose a cycle..."
  [options]="billingCycles"
  [formControl]="billingCycleControl"
  errorMessage="A billing cycle is required."
  errorDisplay="auto"
/>

Full width

Full width of its container by default (see every field above). [fullWidth]="false" shrinks the trigger to fit its selected label instead — useful for a compact field alongside one that should keep growing.

<gog-select label="Country" [options]="countries" [(value)]="fullWidthCountry" />
<gog-select label="Currency" [options]="currencies" [(value)]="currency" [fullWidth]="false" />

Custom chevron & label-less field

Project an <ng-template gogDropdownChevron> to swap the trigger's icon. ariaLabel names a field that has no visible label at all. The chevron slot replaces the chevronTemplate input, deprecated in 21.3.0 and removed in 21.5.0.

<gog-select [options]="sortOptions" [(value)]="sortValue">
  <ng-template gogDropdownChevron>
    <gog-icon name="sort" />
  </ng-template>
</gog-select>

<gog-select
  ariaLabel="Country (no visible label)"
  placeholder="Pick a country"
  [options]="countries"
  [(value)]="ariaOnlyValue"
/>

Append to body & custom panel size

appendToBody portals the panel into document.body — useful inside scrollable or overflow-clipped containers, since the panel escapes the clipping. dropdownWidth and dropdownMaxHeight then take any CSS length to override the trigger-derived size; both apply only with appendToBody. The list below has 20 options, capped to 160px so it scrolls internally.

<gog-select
  label="Country (fixed 220px / 160px panel)"
  [options]="countries"
  [appendToBody]="true"
  dropdownWidth="220px"
  dropdownMaxHeight="160px"
  [(value)]="compactPanelValue"
/>

Your own objects

optionLabel, optionValue and optionDisabled each take a property path — dot-paths included — or a function. A real DTO goes straight in, with no mapping into { id, name } first and nothing lost on the way back out. The defaults are 'name' / 'id' / 'disabled', so code written before 21.3.0 is unaffected; GogDropdownOption is no longer a requirement, just the shape those defaults expect to find.

Set [optionValue]="null" and the control emits the option object itself — the same reference you passed in, not a copy.

id = null · object = null

<!-- A real DTO goes straight in: no mapping into { id, name } first. -->
<gog-select
  label="Assignee"
  optionLabel="profile.fullName"
  optionValue="uuid"
  optionDisabled="suspended"
  [options]="users"
  [(value)]="userId"
/>

<!-- [optionValue]="null" hands back the option object itself. -->
<gog-select
  label="Assignee (object)"
  optionLabel="profile.fullName"
  [optionValue]="null"
  [options]="users"
  [(value)]="userObject"
/>

Filtering

filter puts a search box in the panel, matching case-insensitively on the resolved optionLabel. The query resets when the panel closes, and filterPosition sticks the box to either end of the list. filterMatch swaps the default match for your own predicate — useful for searching a field the label never shows.

<gog-select
  label="Country"
  [filter]="true"
  filterPlaceholder="Search countries…"
  filterEmptyMessage="No country matches"
  [options]="manyCountries"
  [(value)]="filteredCountry"
/>

<!-- filterMatch replaces the default substring match on the label. -->
<gog-select
  label="Assignee"
  optionLabel="profile.fullName"
  optionValue="uuid"
  [filter]="true"
  [filterMatch]="matchNameOrRole"
  [options]="users"
  [(value)]="userId"
/>

Clearable

The clear button is value-driven: it appears once something is selected and vanishes when nothing is. That is the point — it replaces the fake "— not selected —" option teams add to make a choice undoable. It takes the outermost trailing position, with the chevron shifting inward, so the trigger's width stays stable and the destructive control is not on the very edge.

<gog-select label="Plan" [clearable]="true" [options]="plansWithDisabled" [(value)]="plan" />

Custom option rows

A gogDropdownOption template replaces one option row. Its context carries the option itself plus selected, disabled and the already-resolved label — so a custom row can decorate the label rather than re-derive it.

<gog-select
  label="Assignee"
  optionLabel="profile.fullName"
  optionValue="uuid"
  [options]="users"
  [(value)]="slotUserId"
>
  <ng-template gogDropdownOption let-user let-label="label" let-selected="selected">
    <strong>{{ label }}</strong>
    <small>{{ user.profile.role }}</small>
  </ng-template>
</gog-select>

API Reference

Inputs

NameTypeDefaultDescription
valuestring | number | null (model)nullTwo-way bindable selected option id via [(value)]. Also driven by Angular Forms through writeValue/registerOnChange when used with formControlName/[formControl]/ngModel.
labelstring''Field label.
ariaLabelstring''Accessible name for the field when there is no visible label.
inputIdstring''id on the trigger button, and target of the label's for attribute.
placeholderstring'Select...'Text shown while no option is selected.
optionsTOption[][]The list of choices — your own objects. GogDropdownOption ({ id, name, disabled? }) is just the shape the default accessors expect, not a requirement.
optionLabelstring | ((o: TOption) => string)'name'How an option turns into its visible text: a property path (dot-paths included, "profile.fullName") or a function.
optionValuestring | ((o: TOption) => unknown) | null'id'How an option turns into the emitted value. Set it to null and the control emits the option OBJECT itself — the same reference you passed in.
optionDisabledstring | ((o: TOption) => boolean)'disabled'Which options cannot be picked.
clearablebooleanGOG_CONFIG.control.clearable ?? falseAdds a clear button in the outermost trailing position, with the chevron shifting inward when it appears. It shows only once something is selected — which is what removes the need for a fake "— not selected —" option just to make a choice undoable.
clearAriaLabelstring'Clear selection'Accessible name for that clear button.
filterbooleanGOG_CONFIG.dropdown.filter ?? falsePuts a search box in the panel, matching case-insensitively on the resolved optionLabel. The query resets when the panel closes.
filterPosition'top' | 'bottom'GOG_CONFIG.dropdown.filterPosition ?? 'top'Which end of the panel the search box sticks to. It carries a divider on the side facing the list, so it reads as chrome rather than as a row.
filterPlaceholder / filterEmptyMessagestring'Search...' / 'No matches'Wording for the search box and for the empty result.
filterMatch((option: TOption, query: string) => boolean) | nullnullReplaces the default case-insensitive substring match — for searching a field the label does not show, or for fuzzy matching.
floatLabel'none' | 'in' | 'on' | 'over'GOG_CONFIG.floatLabel.variant ?? 'none'Rests the label inside the field like a placeholder and floats it up once something is selected or the field has focus.
floatLabelShowPlaceholderbooleanGOG_CONFIG.floatLabel.showPlaceholder ?? falseReveals the placeholder once the label has floated out of the way.
errorMessagestring''Error text to display. Visibility is governed by errorDisplay.
errorDisplay'auto' | 'manual'GOG_CONFIG.control.errorDisplay ?? 'manual''manual': shown for as long as errorMessage is non-empty — you decide the timing. 'auto': shown once the attached FormControl is touched and invalid; falls back to manual without one.
size'xsm' | 'sm' | 'md' | 'lg' | 'slg'GOG_CONFIG.control.size ?? 'md'Field height, padding, and font size.
disabledbooleanfalseDisables the trigger and closes the panel if it is open.
fullWidthbooleantrueFills its container by default. Set false to shrink to fit the selected label instead.
minWidthstring | nullnull (--gog-select-min-width, 120px)Floor for an auto-width trigger, any CSS length — so a short selection cannot collapse the field to its own chrome.
dropdownDirection'auto' | 'up' | 'down'GOG_CONFIG.dropdown.direction ?? 'auto'Which side the panel opens on. 'auto' flips to whichever side has room in the viewport.
dropdownZIndexnumber | nullnullExplicit stacking order for the panel. Left unset it falls back to the --gog-dropdown-z token.
dropdownWidthstring | nullnullFixed panel width, any CSS length. Applies only with appendToBody. Left unset, the panel sizes to its own content with the trigger width as a floor, capped by --gog-{select,multiselect}-panel-max-width — so picking a short option no longer cuts the longer ones off the list.
dropdownMaxHeightstring | nullnullFixed panel max-height, any CSS length. Applies only with appendToBody.
appendToBodybooleanGOG_CONFIG.dropdown.appendToBody ?? falsePortals the panel into document.body instead of rendering it inline — escapes an ancestor's scroll/overflow clipping. Worth setting app-wide for a layout whose dropdowns generally live inside scrollable containers.
chevronTemplateTemplateRef<unknown> | nullnullDeprecated since 21.3.0, removed in 21.5.0 — project an <ng-template gogDropdownChevron> instead. Still works, and the projected slot wins when both are present.

Content slots

DirectiveContextDescription
gogDropdownOption$implicit, selected, disabled, labelReplaces one option row.
gogDropdownChevron Replaces the trigger's chevron. Wins over the deprecated chevronTemplate input.

Styling Tokens

Every CSS custom property the select paints with. Override any of them — on a single instance, a subtree, or a theme — to restyle it. See the Theming guide for the full token-layering model, or the Theme Generator to tweak these live.

TokenDescription
--gog-select-label-colorField label color.
--gog-select-field-bg / -field-borderField surface and border.
--gog-select-radiusField corner radius.
--gog-select-focus-border / -focus-ringFocus state.
--gog-select-panel-bg / -panel-shadow / -panel-max-widthDropdown panel surface, and the cap on a panel that sizes to its own content rather than to the trigger.
--gog-select-min-widthThe floor an auto-width trigger cannot collapse past (120px).
--gog-select-chevron-color / -chevron-insetDropdown arrow color and inset. Since 21.3.0 the inset lands on --gog-control-icon-offset, the same line as gog-inputfield’s icons — the three controls now line up in a form.
--gog-select-option-hover-bg / -option-selected-colorOption row states.
--gog-select-float-label-reserve / -in-top / -on-bg / -over-gap / -over-reserveFloat-label geometry, derived from the shared --gog-field-float-label-* scale.