Searchbar
The <smart-searchbar> component provides a debounced search input with an optional toggle button. It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. It renders a default SearchbarStandardComponent which can be replaced via SEARCHBAR_STANDARD_COMPONENT_TOKEN.
Usage
<smart-searchbar [options]="options" [(text)]="query" [(show)]="expanded" />
@if (query()) {
<p>Results for "{{ query() }}"</p>
}
Components
SearchbarComponent (<smart-searchbar>)
Main wrapper component. Renders SearchbarStandardComponent by default. When SEARCHBAR_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.
SearchbarStandardComponent (<smart-searchbar-standard>)
Default concrete implementation. Renders:
- a Tailwind-styled
<input type="search">bound to aUntypedFormControlwithdebounceTimefrom options, - a magnifier SVG icon inside the input,
- an optional toggle button (shown when
show()isfalseandoptions.showToggleButtonistrue) that reveals the input, smart:dark:*dark-mode classes.
SearchbarBaseComponent (abstract)
Abstract base directive for extending custom searchbar implementations. Exposes options, cssClass, show and text models, a control signal wrapping UntypedFormControl, and setShow()/tryHide() methods. The base class wires control.valueChanges through debounceTime() in ngAfterViewInit and emits into the text model.
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
options | InputSignal<ISearchbarOptions | undefined> | - | Searchbar configuration |
show | ModelSignal<boolean> | true | Whether the input is visible (two-way bindable) |
text | ModelSignal<string> | required | Debounced search text (two-way bindable) |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
ISearchbarOptions
The placeholder value is rendered through TranslatePipe, so it may be a translation key. If no placeholder is provided, the key 'search' is used.
SEARCHBAR_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default SearchbarStandardComponent with a custom implementation. Provide a Type<SearchbarBaseComponent> to override.
Extending the base class
import {
ChangeDetectionStrategy,
Component,
computed,
input,
signal,
ViewEncapsulation,
} from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import {
ISearchbarOptions,
SEARCHBAR_STANDARD_COMPONENT_TOKEN,
SearchbarBaseComponent,
SearchbarComponent,
} from '@smartsoft001/angular';
@Component({
selector: 'docs-custom-searchbar',
template: `
@if (show()) {
<div [class]="containerClasses()">
<span class="docs-searchbar__icon" aria-hidden="true">⚲</span>
<input
type="search"
class="docs-searchbar__input"
[formControl]="control()"
[placeholder]="options()?.placeholder ?? 'Search'"
[attr.aria-label]="options()?.label ?? 'Search'"
(blur)="tryHide()"
/>
</div>
} @else if (options()?.showToggleButton) {
<button
type="button"
class="docs-searchbar__toggle"
aria-label="Show the search field"
(click)="setShow()"
>
⚲
</button>
}
`,
imports: [ReactiveFormsModule],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomSearchbarComponent extends SearchbarBaseComponent {
// NgComponentOutlet passes 'cssClass' by canonical name, not the 'class' alias.
override cssClass = input<string>('');
// The base class owns the debounced control.valueChanges subscription that
// feeds `text` - do not subscribe again here.
readonly containerClasses = computed(() => {
const classes = ['docs-searchbar'];
const extra = this.cssClass();
if (extra) classes.push(extra);
return classes.join(' ');
});
}
@Component({
selector: 'docs-searchbar-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [SearchbarComponent],
// The token swaps the standard searchbar for the custom one everywhere below
// this component, so consumers keep writing `<smart-searchbar>`.
providers: [
{
provide: SEARCHBAR_STANDARD_COMPONENT_TOKEN,
useValue: CustomSearchbarComponent,
},
],
// NgComponentOutlet forwards `show` and `text` as plain inputs, so values
// travel down into the custom component but its own model changes never
// travel back up to these signals.
template: `
<smart-searchbar [(show)]="show" [(text)]="text" [options]="options" />
`,
})
export class SearchbarCustomExampleComponent {
readonly show = signal(true);
readonly text = signal('');
readonly options: ISearchbarOptions = {
placeholder: 'Search invoices',
label: 'Search invoices',
debounceTime: 300,
showToggleButton: true,
};
}
Source
The component lives in packages/shared/angular/src/lib/components/searchbar and is documented for Claude Code by the angular-components-searchbar skill.