diff --git a/libs/docs/ui5-webcomponents/api-files.ts b/libs/docs/ui5-webcomponents/api-files.ts
index d1fb9c35127..1635af8bc3f 100644
--- a/libs/docs/ui5-webcomponents/api-files.ts
+++ b/libs/docs/ui5-webcomponents/api-files.ts
@@ -40,5 +40,8 @@ export const API_FILES = {
textArea: ['TextArea'],
timePicker: ['TimePicker'],
title: ['Title'],
- toast: ['Toast']
+ toast: ['Toast'],
+ toggleButton: ['ToggleButton'],
+ token: ['Token'],
+ tokenizer: ['Tokenizer']
};
diff --git a/libs/docs/ui5-webcomponents/docs-data.json b/libs/docs/ui5-webcomponents/docs-data.json
index 270756cd9da..4fd7f08ac03 100644
--- a/libs/docs/ui5-webcomponents/docs-data.json
+++ b/libs/docs/ui5-webcomponents/docs-data.json
@@ -141,6 +141,18 @@
{
"url": "ui5-webcomponents/toast",
"name": "Toast"
+ },
+ {
+ "url": "ui5-webcomponents/toggle-button",
+ "name": "Toggle Button"
+ },
+ {
+ "url": "ui5-webcomponents/token",
+ "name": "Token"
+ },
+ {
+ "url": "ui5-webcomponents/tokenizer",
+ "name": "Tokenizer"
}
]
}
diff --git a/libs/docs/ui5-webcomponents/docs-routes.ts b/libs/docs/ui5-webcomponents/docs-routes.ts
index 3f98edf5302..08517ff34ed 100644
--- a/libs/docs/ui5-webcomponents/docs-routes.ts
+++ b/libs/docs/ui5-webcomponents/docs-routes.ts
@@ -154,6 +154,18 @@ const componentRoutes = [
{
path: 'toast',
loadChildren: () => import('@fundamental-ngx/docs/ui5-webcomponents/toast').then(configureLibRoutes)
+ },
+ {
+ path: 'toggle-button',
+ loadChildren: () => import('@fundamental-ngx/docs/ui5-webcomponents/toggle-button').then(configureLibRoutes)
+ },
+ {
+ path: 'token',
+ loadChildren: () => import('@fundamental-ngx/docs/ui5-webcomponents/token').then(configureLibRoutes)
+ },
+ {
+ path: 'tokenizer',
+ loadChildren: () => import('@fundamental-ngx/docs/ui5-webcomponents/tokenizer').then(configureLibRoutes)
}
];
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.html b/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.html
new file mode 100644
index 00000000000..0adcfc09fb0
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.html
@@ -0,0 +1,5 @@
+ Toggle Me
+
+
+ Current state: {{ isPressed() ? 'Pressed' : 'Unpressed' }}
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.ts b/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.ts
new file mode 100644
index 00000000000..0502723b499
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/basic-sample.ts
@@ -0,0 +1,17 @@
+import { Component, signal } from '@angular/core';
+import { Label } from '@fundamental-ngx/ui5-webcomponents/label';
+import { ToggleButton } from '@fundamental-ngx/ui5-webcomponents/toggle-button';
+
+@Component({
+ selector: 'ui5-toggle-button-basic-sample',
+ templateUrl: './basic-sample.html',
+ standalone: true,
+ imports: [ToggleButton, Label]
+})
+export class ToggleButtonBasicSample {
+ readonly isPressed = signal(false);
+
+ onToggleClick(): void {
+ this.isPressed.update(() => !this.isPressed());
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/designs.html b/libs/docs/ui5-webcomponents/toggle-button/examples/designs.html
new file mode 100644
index 00000000000..87e441273d3
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/designs.html
@@ -0,0 +1,14 @@
+
+
+ @for (design of designs; track design) {
+
+
+ {{ design }} Button
+
+
+ State: {{ pressedStates()[design] ? 'Pressed' : 'Unpressed' }}
+
+
+ }
+
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/designs.ts b/libs/docs/ui5-webcomponents/toggle-button/examples/designs.ts
new file mode 100644
index 00000000000..f248b6f98e8
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/designs.ts
@@ -0,0 +1,32 @@
+import { Component, signal } from '@angular/core';
+import { ButtonDesign } from '@fundamental-ngx/ui5-webcomponents';
+import { ToggleButton } from '@fundamental-ngx/ui5-webcomponents/toggle-button';
+
+// Import Fundamental Styles
+import 'fundamental-styles/dist/layout-grid.css';
+import 'fundamental-styles/dist/margins.css';
+
+@Component({
+ selector: 'ui5-toggle-button-designs-sample',
+ templateUrl: './designs.html',
+ standalone: true,
+ imports: [ToggleButton]
+})
+export class ToggleButtonDesignsSample {
+ readonly designs: Array = Object.keys(ButtonDesign) as Array;
+ readonly pressedStates = signal>({
+ Default: false,
+ Emphasized: false,
+ Positive: false,
+ Negative: false,
+ Transparent: false,
+ Attention: false
+ });
+
+ onToggle(design: string): void {
+ this.pressedStates.update((states) => ({
+ ...states,
+ [design]: !states[design]
+ }));
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/icons.html b/libs/docs/ui5-webcomponents/toggle-button/examples/icons.html
new file mode 100644
index 00000000000..03110b0385d
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/icons.html
@@ -0,0 +1,59 @@
+
+
+
Icon Only:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Icon with Text:
+
+
+
+
+
+ Add to Favorites
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/icons.ts b/libs/docs/ui5-webcomponents/toggle-button/examples/icons.ts
new file mode 100644
index 00000000000..798547a648a
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/icons.ts
@@ -0,0 +1,40 @@
+import { Component, signal } from '@angular/core';
+import { ToggleButton } from '@fundamental-ngx/ui5-webcomponents/toggle-button';
+
+// Import SAP Icons
+import '@ui5/webcomponents-icons/dist/bookmark.js';
+import '@ui5/webcomponents-icons/dist/favorite.js';
+import '@ui5/webcomponents-icons/dist/media-pause.js';
+import '@ui5/webcomponents-icons/dist/media-play.js';
+import '@ui5/webcomponents-icons/dist/sound-off.js';
+import '@ui5/webcomponents-icons/dist/sound.js';
+import '@ui5/webcomponents-icons/dist/unfavorite.js';
+
+@Component({
+ selector: 'ui5-toggle-button-icons-sample',
+ templateUrl: './icons.html',
+ standalone: true,
+ imports: [ToggleButton]
+})
+export class ToggleButtonIconsSample {
+ readonly favoritePressed = signal(false);
+ readonly bookmarkPressed = signal(false);
+ readonly playPressed = signal(false);
+ readonly soundPressed = signal(true);
+
+ toggleFavorite(): void {
+ this.favoritePressed.update(() => !this.favoritePressed());
+ }
+
+ toggleBookmark(): void {
+ this.bookmarkPressed.update(() => !this.bookmarkPressed());
+ }
+
+ togglePlay(): void {
+ this.playPressed.update(() => !this.playPressed());
+ }
+
+ toggleSound(): void {
+ this.soundPressed.update(() => !this.soundPressed());
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.html b/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.html
new file mode 100644
index 00000000000..f6bd8b644b2
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.html
@@ -0,0 +1,65 @@
+
+
+
+
Design:
+
+ @for (design of designs; track design) {
+ {{ design }}
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Preview:
+
+ @if (hasText()) { Toggle Button }
+
+
+
+
Configuration:
+
+ - Design: {{ selectedDesign() }}
+ - State: {{ isPressed() ? 'Pressed' : 'Unpressed' }}
+ - Disabled: {{ isDisabled() ? 'Yes' : 'No' }}
+ - Icon: {{ hasIcon() ? 'Yes' : 'No' }}
+ - Text: {{ hasText() ? 'Yes' : 'No' }}
+ - Loading: {{ isLoading() ? 'Yes' : 'No' }}
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.ts b/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.ts
new file mode 100644
index 00000000000..1cb6c3b0670
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/examples/interactive.ts
@@ -0,0 +1,52 @@
+import { Component, signal, WritableSignal } from '@angular/core';
+import { ButtonDesign, CheckBox, Option, Select } from '@fundamental-ngx/ui5-webcomponents';
+import { ToggleButton } from '@fundamental-ngx/ui5-webcomponents/toggle-button';
+
+// Import SAP Icon
+import '@ui5/webcomponents-icons/dist/settings.js';
+
+@Component({
+ selector: 'ui5-toggle-button-interactive-sample',
+ templateUrl: './interactive.html',
+ standalone: true,
+ imports: [ToggleButton, Select, Option, CheckBox]
+})
+export class ToggleButtonInteractiveSample {
+ readonly designs: Array = Object.keys(ButtonDesign) as Array;
+
+ readonly selectedDesign: WritableSignal = signal('Default');
+ readonly isPressed = signal(false);
+ readonly isDisabled = signal(false);
+ readonly hasIcon = signal(false);
+ readonly hasText = signal(true);
+ readonly isLoading = signal(false);
+
+ onDesignChange(event: any): void {
+ const selectedOption = event.detail?.selectedOption;
+ if (selectedOption) {
+ this.selectedDesign.set(selectedOption.getAttribute('value') || 'Default');
+ }
+ }
+
+ onToggleClick(): void {
+ if (!this.isDisabled() && !this.isLoading()) {
+ this.isPressed.update((v) => !v);
+ }
+ }
+
+ onDisabledChange(event: any): void {
+ this.isDisabled.set(event.target.checked);
+ }
+
+ onIconChange(event: any): void {
+ this.hasIcon.set(event.target.checked);
+ }
+
+ onTextChange(event: any): void {
+ this.hasText.set(event.target.checked);
+ }
+
+ onLoadingChange(event: any): void {
+ this.isLoading.set(event.target.checked);
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.html b/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.html
new file mode 100644
index 00000000000..62b299278d5
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.ts b/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.ts
new file mode 100644
index 00000000000..97b3c72236b
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/header/toggle-button-header.ts
@@ -0,0 +1,19 @@
+import { Component } from '@angular/core';
+import {
+ DescriptionComponent,
+ DocPageComponent,
+ HeaderComponent,
+ HeaderTabsComponent,
+ ImportComponent
+} from '@fundamental-ngx/docs/shared';
+
+@Component({
+ selector: 'ui5-toggle-button-header',
+ templateUrl: './toggle-button-header.html',
+ standalone: true,
+ imports: [DocPageComponent, HeaderComponent, DescriptionComponent, ImportComponent, HeaderTabsComponent]
+})
+export class ToggleButtonHeader {
+ componentName = 'ToggleButton';
+ packageName = '@ui5/webcomponents';
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/index.ts b/libs/docs/ui5-webcomponents/toggle-button/index.ts
new file mode 100644
index 00000000000..00f11d92ffe
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/index.ts
@@ -0,0 +1,19 @@
+import { Routes } from '@angular/router';
+import { ToggleButtonHeader } from './header/toggle-button-header';
+import { ToggleButtonDocs } from './toggle-button-docs';
+
+export const ROUTES: Routes = [
+ {
+ path: '',
+ component: ToggleButtonHeader,
+ data: { primary: true },
+ children: [
+ {
+ path: '',
+ component: ToggleButtonDocs
+ }
+ ]
+ }
+];
+export const LIBRARY_NAME = 'toggle-button';
+export const API_FILE_KEY = 'toggleButton';
diff --git a/libs/docs/ui5-webcomponents/toggle-button/project.json b/libs/docs/ui5-webcomponents/toggle-button/project.json
new file mode 100644
index 00000000000..43567232613
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/project.json
@@ -0,0 +1,18 @@
+{
+ "name": "docs-ui5-webcomponents-toggle-button",
+ "$schema": "../../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/docs/ui5-webcomponents/toggle-button",
+ "prefix": "ui5-doc",
+ "projectType": "library",
+ "tags": ["type:lib", "scope:docs"],
+ "targets": {
+ "e2e": {
+ "executor": "@fundamental-ngx/nx-plugin:e2e-test",
+ "options": {
+ "e2eFiles": ["libs/docs/ui5-webcomponents/toggle-button/e2e/**/*.e2e-spec.ts"],
+ "devServerTarget": "docs:serve:e2e"
+ },
+ "outputs": ["{workspaceRoot}/allure-results/docs-ui5-webcomponents-toggle-button"]
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.html b/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.html
new file mode 100644
index 00000000000..213bfc32c54
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.html
@@ -0,0 +1,42 @@
+Basic Example
+
+ The UI5 Toggle Button component allows users to switch between two states: pressed and unpressed. It is commonly
+ used for features like favorites, bookmarks, or any binary choice that needs to persist visually.
+
+
+
+
+
+
+Toggle Button Designs
+
+ The design property controls the visual appearance and semantic meaning of the toggle button. Available
+ designs include Default, Emphasized, Positive, Negative, Transparent, and Attention, each conveying different levels
+ of importance or semantic intent.
+
+
+
+
+
+
+Toggle Button with Icons
+
+ Toggle buttons can display icons to represent their state or purpose more visually. The icon property
+ accepts any icon from the SAP icon font. Icons can be used alone or combined with text to create more expressive
+ toggle buttons.
+
+
+
+
+
+
+Interactive Configuration
+
+ This comprehensive example demonstrates all toggle button properties and allows you to experiment with different
+ configurations. You can customize the design, toggle the pressed state, enable/disable the button, add icons,
+ show/hide text, and simulate a loading state.
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.ts b/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.ts
new file mode 100644
index 00000000000..255591cb02c
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/toggle-button-docs.ts
@@ -0,0 +1,97 @@
+import { Component, computed, inject, Injector, runInInjectionContext } from '@angular/core';
+import {
+ CodeExampleComponent,
+ ComponentExampleComponent,
+ DescriptionComponent,
+ DocsSectionTitleComponent,
+ ExampleFile,
+ getAssetFromModuleAssets
+} from '@fundamental-ngx/docs/shared';
+import { ToggleButtonBasicSample } from './examples/basic-sample';
+import { ToggleButtonDesignsSample } from './examples/designs';
+import { ToggleButtonIconsSample } from './examples/icons';
+import { ToggleButtonInteractiveSample } from './examples/interactive';
+
+const basicSampleHtml = 'basic-sample.html';
+const basicSampleTs = 'basic-sample.ts';
+const designsHtml = 'designs.html';
+const designsTs = 'designs.ts';
+const iconsHtml = 'icons.html';
+const iconsTs = 'icons.ts';
+const interactiveHtml = 'interactive.html';
+const interactiveTs = 'interactive.ts';
+
+@Component({
+ selector: 'ui5-toggle-button-docs',
+ templateUrl: './toggle-button-docs.html',
+ standalone: true,
+ imports: [
+ DocsSectionTitleComponent,
+ DescriptionComponent,
+ ComponentExampleComponent,
+ CodeExampleComponent,
+ ToggleButtonBasicSample,
+ ToggleButtonDesignsSample,
+ ToggleButtonIconsSample,
+ ToggleButtonInteractiveSample
+ ]
+})
+export class ToggleButtonDocs {
+ private injector = inject(Injector);
+
+ basicSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(basicSampleHtml)),
+ fileName: 'basic-sample'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(basicSampleTs)),
+ fileName: 'basic-sample',
+ component: 'ToggleButtonBasicSample'
+ }
+ ]);
+
+ designsSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(designsHtml)),
+ fileName: 'designs'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(designsTs)),
+ fileName: 'designs',
+ component: 'ToggleButtonDesignsSample'
+ }
+ ]);
+
+ iconsSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(iconsHtml)),
+ fileName: 'icons'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(iconsTs)),
+ fileName: 'icons',
+ component: 'ToggleButtonIconsSample'
+ }
+ ]);
+
+ interactiveSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(interactiveHtml)),
+ fileName: 'interactive'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(interactiveTs)),
+ fileName: 'interactive',
+ component: 'ToggleButtonInteractiveSample'
+ }
+ ]);
+}
diff --git a/libs/docs/ui5-webcomponents/toggle-button/tsconfig.json b/libs/docs/ui5-webcomponents/toggle-button/tsconfig.json
new file mode 100644
index 00000000000..26b852b9336
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/toggle-button/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "../../../../tsconfig.base.json",
+ "files": [],
+ "include": ["**/*.ts"],
+ "compilerOptions": {
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitReturns": false,
+ "noFallthroughCasesInSwitch": true,
+ "target": "es2020",
+ "outDir": "../../../../dist/out-tsc",
+ "declaration": true,
+ "declarationMap": true,
+ "inlineSources": true,
+ "types": []
+ },
+ "exclude": ["**/*.test.ts", "**/*.spec.ts", "**/*.e2e-spec.ts"]
+}
diff --git a/libs/docs/ui5-webcomponents/token/examples/basic-sample.html b/libs/docs/ui5-webcomponents/token/examples/basic-sample.html
new file mode 100644
index 00000000000..c9d7170a6fa
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/examples/basic-sample.html
@@ -0,0 +1,24 @@
+
+
+
+
+ @for (token of tokens(); track token.id) {
+
+
+ }
+
+
+
Selected Tokens:
+
+ @if (selectedTokens.length > 0) { {{ selectedTokenTexts }} } @else {
+ No tokens selected
+ }
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/token/examples/basic-sample.ts b/libs/docs/ui5-webcomponents/token/examples/basic-sample.ts
new file mode 100644
index 00000000000..e5c5c979a70
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/examples/basic-sample.ts
@@ -0,0 +1,29 @@
+import { Component, signal } from '@angular/core';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+
+@Component({
+ selector: 'ui5-token-basic-sample',
+ templateUrl: './basic-sample.html',
+ standalone: true,
+ imports: [Token]
+})
+export class TokenBasicSample {
+ readonly tokens = signal([
+ { id: 1, text: 'Technology', selected: false },
+ { id: 2, text: 'Innovation', selected: false },
+ { id: 3, text: 'Design', selected: false },
+ { id: 4, text: 'Development', selected: false }
+ ]);
+
+ get selectedTokens(): Array<{ id: number; text: string; selected: boolean }> {
+ return this.tokens().filter((t) => t.selected);
+ }
+
+ get selectedTokenTexts(): string {
+ return this.selectedTokens.map((t) => t.text).join(', ');
+ }
+
+ toggleSelection(tokenId: number): void {
+ this.tokens.update((tokens) => tokens.map((t) => (t.id === tokenId ? { ...t, selected: !t.selected } : t)));
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.html b/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.html
new file mode 100644
index 00000000000..9f6deb3a496
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.html
@@ -0,0 +1,11 @@
+
+ @for (tag of availableTags(); track tag.text) {
+
+ }
+
diff --git a/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.ts b/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.ts
new file mode 100644
index 00000000000..d69b3027574
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/examples/token-in-multi-input.ts
@@ -0,0 +1,39 @@
+import { Component, signal, viewChild } from '@angular/core';
+import { MultiInput } from '@fundamental-ngx/ui5-webcomponents';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+
+@Component({
+ selector: 'ui5-token-in-multi-input-sample',
+ templateUrl: './token-in-multi-input.html',
+ standalone: true,
+ imports: [MultiInput, Token]
+})
+export class TokenInMultiInputSample {
+ readonly availableTags = signal([
+ { text: 'Frontend' },
+ { text: 'Backend' },
+ { text: 'Database' },
+ { text: 'DevOps' },
+ { text: 'Cloud' },
+ { text: 'Security' }
+ ]);
+
+ readonly multiInput = viewChild('multiInput');
+
+ onInputChange(event: any): void {
+ const inputValue = event.target.value;
+ this.availableTags.update(() => [...this.availableTags(), { text: inputValue }]);
+
+ const multiInput = this.multiInput();
+ if (multiInput) {
+ multiInput.element.value = '';
+ }
+ }
+
+ onTokenDelete(event: any): void {
+ const tokens = event.detail?.tokens;
+ if (tokens) {
+ tokens.forEach((token) => token.remove());
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/token/header/token-header.html b/libs/docs/ui5-webcomponents/token/header/token-header.html
new file mode 100644
index 00000000000..81c580b926e
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/header/token-header.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/token/header/token-header.ts b/libs/docs/ui5-webcomponents/token/header/token-header.ts
new file mode 100644
index 00000000000..7a187347d54
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/header/token-header.ts
@@ -0,0 +1,19 @@
+import { Component } from '@angular/core';
+import {
+ DescriptionComponent,
+ DocPageComponent,
+ HeaderComponent,
+ HeaderTabsComponent,
+ ImportComponent
+} from '@fundamental-ngx/docs/shared';
+
+@Component({
+ selector: 'ui5-token-header',
+ templateUrl: './token-header.html',
+ standalone: true,
+ imports: [DocPageComponent, HeaderComponent, DescriptionComponent, ImportComponent, HeaderTabsComponent]
+})
+export class TokenHeader {
+ componentName = 'Token';
+ packageName = '@ui5/webcomponents';
+}
diff --git a/libs/docs/ui5-webcomponents/token/index.ts b/libs/docs/ui5-webcomponents/token/index.ts
new file mode 100644
index 00000000000..32b9140c85f
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/index.ts
@@ -0,0 +1,19 @@
+import { Routes } from '@angular/router';
+import { TokenHeader } from './header/token-header';
+import { TokenDocs } from './token-docs';
+
+export const ROUTES: Routes = [
+ {
+ path: '',
+ component: TokenHeader,
+ data: { primary: true },
+ children: [
+ {
+ path: '',
+ component: TokenDocs
+ }
+ ]
+ }
+];
+export const LIBRARY_NAME = 'token';
+export const API_FILE_KEY = 'token';
diff --git a/libs/docs/ui5-webcomponents/token/project.json b/libs/docs/ui5-webcomponents/token/project.json
new file mode 100644
index 00000000000..f6c32883b1a
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/project.json
@@ -0,0 +1,18 @@
+{
+ "name": "docs-ui5-webcomponents-token",
+ "$schema": "../../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/docs/ui5-webcomponents/token",
+ "prefix": "ui5-doc",
+ "projectType": "library",
+ "tags": ["type:lib", "scope:docs"],
+ "targets": {
+ "e2e": {
+ "executor": "@fundamental-ngx/nx-plugin:e2e-test",
+ "options": {
+ "e2eFiles": ["libs/docs/ui5-webcomponents/token/e2e/**/*.e2e-spec.ts"],
+ "devServerTarget": "docs:serve:e2e"
+ },
+ "outputs": ["{workspaceRoot}/allure-results/docs-ui5-webcomponents-token"]
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/token/token-docs.html b/libs/docs/ui5-webcomponents/token/token-docs.html
new file mode 100644
index 00000000000..6fa6ae43b81
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/token-docs.html
@@ -0,0 +1,15 @@
+Basic Example
+
+
+
+
+
+Token in Multi Input
+
+ You can Remove tokens by clicking the "X" button and add tokens by typing something in the input field, followed by
+ "ENTER" or focus out.
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/token/token-docs.ts b/libs/docs/ui5-webcomponents/token/token-docs.ts
new file mode 100644
index 00000000000..eda23b8086a
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/token-docs.ts
@@ -0,0 +1,61 @@
+import { Component, computed, inject, Injector, runInInjectionContext } from '@angular/core';
+import {
+ CodeExampleComponent,
+ ComponentExampleComponent,
+ DescriptionComponent,
+ DocsSectionTitleComponent,
+ ExampleFile,
+ getAssetFromModuleAssets
+} from '@fundamental-ngx/docs/shared';
+import { TokenBasicSample } from './examples/basic-sample';
+import { TokenInMultiInputSample } from './examples/token-in-multi-input';
+
+const basicSampleHtml = 'basic-sample.html';
+const basicSampleTs = 'basic-sample.ts';
+const tokenInMultiInputHtml = 'token-in-multi-input.html';
+const tokenInMultiInputTs = 'token-in-multi-input.ts';
+
+@Component({
+ selector: 'ui5-token-docs',
+ templateUrl: './token-docs.html',
+ standalone: true,
+ imports: [
+ DocsSectionTitleComponent,
+ DescriptionComponent,
+ ComponentExampleComponent,
+ CodeExampleComponent,
+ TokenBasicSample,
+ TokenInMultiInputSample
+ ]
+})
+export class TokenDocs {
+ private injector = inject(Injector);
+
+ basicSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(basicSampleHtml)),
+ fileName: 'basic-sample'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(basicSampleTs)),
+ fileName: 'basic-sample',
+ component: 'TokenBasicSample'
+ }
+ ]);
+
+ tokenInMultiInputSampleFiles = computed((): ExampleFile[] => [
+ {
+ language: 'html',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(tokenInMultiInputHtml)),
+ fileName: 'token-in-multi-input'
+ },
+ {
+ language: 'typescript',
+ code: runInInjectionContext(this.injector, () => getAssetFromModuleAssets(tokenInMultiInputTs)),
+ fileName: 'token-in-multi-input',
+ component: 'TokenInMultiInputSample'
+ }
+ ]);
+}
diff --git a/libs/docs/ui5-webcomponents/token/tsconfig.json b/libs/docs/ui5-webcomponents/token/tsconfig.json
new file mode 100644
index 00000000000..26b852b9336
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/token/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "../../../../tsconfig.base.json",
+ "files": [],
+ "include": ["**/*.ts"],
+ "compilerOptions": {
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitReturns": false,
+ "noFallthroughCasesInSwitch": true,
+ "target": "es2020",
+ "outDir": "../../../../dist/out-tsc",
+ "declaration": true,
+ "declarationMap": true,
+ "inlineSources": true,
+ "types": []
+ },
+ "exclude": ["**/*.test.ts", "**/*.spec.ts", "**/*.e2e-spec.ts"]
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.html b/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.html
new file mode 100644
index 00000000000..ae958f4b94f
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.html
@@ -0,0 +1,5 @@
+
+ @for (token of tokens(); track token.id) {
+
+ }
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.ts b/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.ts
new file mode 100644
index 00000000000..f3df28fee60
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/basic-sample.ts
@@ -0,0 +1,26 @@
+import { Component, signal } from '@angular/core';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+import { Tokenizer } from '@fundamental-ngx/ui5-webcomponents/tokenizer';
+
+@Component({
+ selector: 'ui5-tokenizer-basic-sample',
+ templateUrl: './basic-sample.html',
+ standalone: true,
+ imports: [Tokenizer, Token]
+})
+export class TokenizerBasicSample {
+ tokens = signal([
+ { id: 1, text: 'Product A', value: 'product-a' },
+ { id: 2, text: 'Product B', value: 'product-b' },
+ { id: 3, text: 'Product C', value: 'product-c' },
+ { id: 4, text: 'Product D', value: 'product-d' }
+ ]);
+
+ onTokenDelete(event: any): void {
+ const tokens = event.detail?.tokens;
+
+ if (tokens) {
+ tokens.forEach((token) => token.remove());
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.html b/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.html
new file mode 100644
index 00000000000..b5f7ffdec2c
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.html
@@ -0,0 +1,5 @@
+
+ @for (tag of tags(); track tag.id) {
+
+ }
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.ts b/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.ts
new file mode 100644
index 00000000000..a0f32e3e989
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/clear-all.ts
@@ -0,0 +1,32 @@
+import { Component, signal } from '@angular/core';
+import { Button } from '@fundamental-ngx/ui5-webcomponents/button';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+import { Tokenizer } from '@fundamental-ngx/ui5-webcomponents/tokenizer';
+
+@Component({
+ selector: 'ui5-tokenizer-clear-all-sample',
+ templateUrl: './clear-all.html',
+ standalone: true,
+ imports: [Tokenizer, Token, Button]
+})
+export class TokenizerClearAllSample {
+ tags = signal([
+ { id: 1, text: 'JavaScript' },
+ { id: 2, text: 'TypeScript' },
+ { id: 3, text: 'Angular' },
+ { id: 4, text: 'React' },
+ { id: 5, text: 'Vue' },
+ { id: 6, text: 'Node.js' },
+ { id: 7, text: 'Python' },
+ { id: 8, text: 'Java' }
+ ]);
+
+ /*
+ * This method is fired upon deleting a single token as well as when "Clear All" button is clicked.
+ * The difference between the two is the number of elements in event.detail.tokens
+ */
+ onTokenDelete(event: CustomEvent): void {
+ const tokenElements = event.detail.tokens;
+ tokenElements.forEach((token) => token.remove());
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.html b/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.html
new file mode 100644
index 00000000000..4d0cc04a1cc
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.html
@@ -0,0 +1,23 @@
+
+
+
+
Single Line (Default)
+
+ @for (category of categories(); track category) {
+
+ }
+
+
+
+
+
+
+
Multi-line
+
+ @for (category of categories(); track category) {
+
+ }
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.ts b/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.ts
new file mode 100644
index 00000000000..5dffd5c6e71
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/multi-line.ts
@@ -0,0 +1,45 @@
+import { NgStyle } from '@angular/common';
+import { Component, signal } from '@angular/core';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+import { Tokenizer } from '@fundamental-ngx/ui5-webcomponents/tokenizer';
+
+@Component({
+ selector: 'ui5-tokenizer-multi-line-sample',
+ templateUrl: './multi-line.html',
+ standalone: true,
+ imports: [Tokenizer, Token, NgStyle]
+})
+export class TokenizerMultiLineSample {
+ categories = signal([
+ 'Electronics',
+ 'Home & Garden',
+ 'Sports & Outdoors',
+ 'Books & Media',
+ 'Clothing & Accessories',
+ 'Food & Beverages',
+ 'Health & Beauty',
+ 'Toys & Games',
+ 'Automotive',
+ 'Office Supplies',
+ 'Pet Supplies',
+ 'Jewelry',
+ 'Baby Products',
+ 'Musical Instruments'
+ ]);
+
+ onSingleLineTokenDelete(event: any): void {
+ const tokens = event.detail?.tokens;
+
+ if (tokens) {
+ tokens.forEach((token) => token.remove());
+ }
+ }
+
+ onMultiLineTokenDelete(event: any): void {
+ const tokens = event.detail?.tokens;
+
+ if (tokens) {
+ tokens.forEach((token) => token.remove());
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.html b/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.html
new file mode 100644
index 00000000000..43239358a00
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.html
@@ -0,0 +1,5 @@
+
+ @for (option of selectedOptions(); track option) {
+
+ }
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.ts b/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.ts
new file mode 100644
index 00000000000..a9240ff4716
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/examples/readonly.ts
@@ -0,0 +1,15 @@
+import { Component, signal } from '@angular/core';
+import { Token } from '@fundamental-ngx/ui5-webcomponents/token';
+import { Tokenizer } from '@fundamental-ngx/ui5-webcomponents/tokenizer';
+
+@Component({
+ selector: 'ui5-tokenizer-readonly-sample',
+ templateUrl: './readonly.html',
+ standalone: true,
+ imports: [Tokenizer, Token]
+})
+export class TokenizerReadonlySample {
+ isReadonly = signal(true);
+
+ selectedOptions = signal(['Option 1', 'Option 2', 'Option 3', 'Option 4']);
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.html b/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.html
new file mode 100644
index 00000000000..e984704c04b
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.ts b/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.ts
new file mode 100644
index 00000000000..56189092d6f
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/header/tokenizer-header.ts
@@ -0,0 +1,19 @@
+import { Component } from '@angular/core';
+import {
+ DescriptionComponent,
+ DocPageComponent,
+ HeaderComponent,
+ HeaderTabsComponent,
+ ImportComponent
+} from '@fundamental-ngx/docs/shared';
+
+@Component({
+ selector: 'ui5-tokenizer-header',
+ templateUrl: './tokenizer-header.html',
+ standalone: true,
+ imports: [DocPageComponent, HeaderComponent, DescriptionComponent, ImportComponent, HeaderTabsComponent]
+})
+export class TokenizerHeader {
+ componentName = 'Tokenizer';
+ packageName = '@ui5/webcomponents';
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/index.ts b/libs/docs/ui5-webcomponents/tokenizer/index.ts
new file mode 100644
index 00000000000..77ff11fa860
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/index.ts
@@ -0,0 +1,19 @@
+import { Routes } from '@angular/router';
+import { TokenizerHeader } from './header/tokenizer-header';
+import { TokenizerDocs } from './tokenizer-docs';
+
+export const ROUTES: Routes = [
+ {
+ path: '',
+ component: TokenizerHeader,
+ data: { primary: true },
+ children: [
+ {
+ path: '',
+ component: TokenizerDocs
+ }
+ ]
+ }
+];
+export const LIBRARY_NAME = 'tokenizer';
+export const API_FILE_KEY = 'tokenizer';
diff --git a/libs/docs/ui5-webcomponents/tokenizer/project.json b/libs/docs/ui5-webcomponents/tokenizer/project.json
new file mode 100644
index 00000000000..ef0937167b6
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/project.json
@@ -0,0 +1,18 @@
+{
+ "name": "docs-ui5-webcomponents-tokenizer",
+ "$schema": "../../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/docs/ui5-webcomponents/tokenizer",
+ "prefix": "ui5-doc",
+ "projectType": "library",
+ "tags": ["type:lib", "scope:docs"],
+ "targets": {
+ "e2e": {
+ "executor": "@fundamental-ngx/nx-plugin:e2e-test",
+ "options": {
+ "e2eFiles": ["libs/docs/ui5-webcomponents/tokenizer/e2e/**/*.e2e-spec.ts"],
+ "devServerTarget": "docs:serve:e2e"
+ },
+ "outputs": ["{workspaceRoot}/allure-results/docs-ui5-webcomponents-tokenizer"]
+ }
+ }
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.html b/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.html
new file mode 100644
index 00000000000..c1ad28404ba
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.html
@@ -0,0 +1,34 @@
+ Basic Tokenizer
+
+
+
+
+
+ Multi-line Tokenizer
+
+ With multiLine enabled, tokens are displayed across multiple lines for improved readability.
+
+
+
+
+
+
+ Read-only Tokenizer
+
+ A read-only tokenizer prevents token deletion and provides visual feedback that the component is not editable. Use
+ the readonly property to make the tokenizer read-only.
+
+
+
+
+
+
+ Clear All Button
+
+ When multiLine is enabled, you can also show a "Clear All" button by setting the
+ showClearAll property. This button allows users to delete all tokens at once.
+
+
+
+
+
diff --git a/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.ts b/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.ts
new file mode 100644
index 00000000000..a0a4681f357
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/tokenizer-docs.ts
@@ -0,0 +1,101 @@
+import { Component, signal } from '@angular/core';
+import {
+ CodeExampleComponent,
+ ComponentExampleComponent,
+ DescriptionComponent,
+ DocsSectionTitleComponent,
+ ExampleFile,
+ getAssetFromModuleAssets
+} from '@fundamental-ngx/docs/shared';
+import { TokenizerBasicSample } from './examples/basic-sample';
+import { TokenizerClearAllSample } from './examples/clear-all';
+import { TokenizerMultiLineSample } from './examples/multi-line';
+import { TokenizerReadonlySample } from './examples/readonly';
+
+const basicSampleHtml = 'basic-sample.html';
+const basicSampleTs = 'basic-sample.ts';
+const multiLineHtml = 'multi-line.html';
+const multiLineTs = 'multi-line.ts';
+const readonlyHtml = 'readonly.html';
+const readonlyTs = 'readonly.ts';
+const clearAllHtml = 'clear-all.html';
+const clearAllTs = 'clear-all.ts';
+
+@Component({
+ selector: 'ui5-tokenizer-docs',
+ templateUrl: './tokenizer-docs.html',
+ standalone: true,
+ imports: [
+ DocsSectionTitleComponent,
+ ComponentExampleComponent,
+ CodeExampleComponent,
+ DescriptionComponent,
+ TokenizerBasicSample,
+ TokenizerMultiLineSample,
+ TokenizerReadonlySample,
+ TokenizerClearAllSample
+ ]
+})
+export class TokenizerDocs {
+ private readonly basicExampleFiles = signal([
+ {
+ language: 'html',
+ code: getAssetFromModuleAssets(basicSampleHtml),
+ fileName: 'basic-sample'
+ },
+ {
+ language: 'typescript',
+ component: 'TokenizerBasicSample',
+ code: getAssetFromModuleAssets(basicSampleTs),
+ fileName: 'basic-sample'
+ }
+ ]);
+
+ private readonly multiLineExampleFiles = signal([
+ {
+ language: 'html',
+ code: getAssetFromModuleAssets(multiLineHtml),
+ fileName: 'multi-line'
+ },
+ {
+ language: 'typescript',
+ component: 'TokenizerMultiLineSample',
+ code: getAssetFromModuleAssets(multiLineTs),
+ fileName: 'multi-line'
+ }
+ ]);
+
+ private readonly readonlyExampleFiles = signal([
+ {
+ language: 'html',
+ code: getAssetFromModuleAssets(readonlyHtml),
+ fileName: 'readonly'
+ },
+ {
+ language: 'typescript',
+ component: 'TokenizerReadonlySample',
+ code: getAssetFromModuleAssets(readonlyTs),
+ fileName: 'readonly'
+ }
+ ]);
+
+ private readonly clearAllExampleFiles = signal([
+ {
+ language: 'html',
+ code: getAssetFromModuleAssets(clearAllHtml),
+ fileName: 'clear-all'
+ },
+ {
+ language: 'typescript',
+ component: 'TokenizerClearAllSample',
+ code: getAssetFromModuleAssets(clearAllTs),
+ fileName: 'clear-all'
+ }
+ ]);
+
+ // Computed properties for code examples
+ basicFiles = this.basicExampleFiles.asReadonly();
+ multiLineFiles = this.multiLineExampleFiles.asReadonly();
+ readonlyFiles = this.readonlyExampleFiles.asReadonly();
+ clearAllFiles = this.clearAllExampleFiles.asReadonly();
+}
diff --git a/libs/docs/ui5-webcomponents/tokenizer/tsconfig.json b/libs/docs/ui5-webcomponents/tokenizer/tsconfig.json
new file mode 100644
index 00000000000..26b852b9336
--- /dev/null
+++ b/libs/docs/ui5-webcomponents/tokenizer/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "../../../../tsconfig.base.json",
+ "files": [],
+ "include": ["**/*.ts"],
+ "compilerOptions": {
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitReturns": false,
+ "noFallthroughCasesInSwitch": true,
+ "target": "es2020",
+ "outDir": "../../../../dist/out-tsc",
+ "declaration": true,
+ "declarationMap": true,
+ "inlineSources": true,
+ "types": []
+ },
+ "exclude": ["**/*.test.ts", "**/*.spec.ts", "**/*.e2e-spec.ts"]
+}