diff --git a/src/bundle/Resources/public/ts/components/chip.ts b/src/bundle/Resources/public/ts/components/chip.ts
new file mode 100644
index 00000000..33bb4e93
--- /dev/null
+++ b/src/bundle/Resources/public/ts/components/chip.ts
@@ -0,0 +1,36 @@
+import { Base } from '../partials';
+
+interface ChipConfig {
+ onDelete?: (event: MouseEvent) => void;
+}
+
+export default class Chip extends Base {
+ private deleteButton: HTMLButtonElement | null;
+ private onDelete?: (event: MouseEvent) => void;
+
+ constructor(container: HTMLDivElement, config: ChipConfig = {}) {
+ super(container);
+
+ this.deleteButton = this._container.querySelector('.ids-chip__delete');
+ this.onDelete = config.onDelete;
+ }
+
+ protected handleDelete(event: MouseEvent): void {
+ event.stopPropagation();
+
+ if (this.onDelete) {
+ this.onDelete(event);
+ }
+ }
+
+ protected initDeleteButton(): void {
+ if (this.deleteButton) {
+ this.deleteButton.addEventListener('click', this.handleDelete.bind(this));
+ }
+ }
+
+ public init(): void {
+ super.init();
+ this.initDeleteButton();
+ }
+}
diff --git a/src/bundle/Resources/translations/ibexa_design_system_twig.en.xliff b/src/bundle/Resources/translations/ibexa_design_system_twig.en.xliff
index 780deca8..f88d8415 100644
--- a/src/bundle/Resources/translations/ibexa_design_system_twig.en.xliff
+++ b/src/bundle/Resources/translations/ibexa_design_system_twig.en.xliff
@@ -6,6 +6,11 @@
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
+
+ Delete
+ Delete
+ key: ibexa.chip.delete-btn.label
+
Clear
Clear
diff --git a/src/bundle/Resources/views/themes/standard/design_system/components/chip.html.twig b/src/bundle/Resources/views/themes/standard/design_system/components/chip.html.twig
new file mode 100644
index 00000000..39052d37
--- /dev/null
+++ b/src/bundle/Resources/views/themes/standard/design_system/components/chip.html.twig
@@ -0,0 +1,29 @@
+{% trans_default_domain 'ibexa_design_system_twig' %}
+
+{% set chip_classes =
+ html_classes(
+ 'ids-chip',
+ {
+ 'ids-chip--error': error,
+ 'ids-chip--disabled': disabled,
+ },
+ attributes.render('class') ?? ''
+ )
+%}
+{% set delete_msg = 'ibexa.chip.delete-btn.label'|trans|desc('Delete') %}
+
+
+
+ {{ block('content') }}
+
+ {% if is_deletable %}
+
+ {% endif %}
+
diff --git a/src/lib/Twig/Components/Chip.php b/src/lib/Twig/Components/Chip.php
new file mode 100644
index 00000000..55514fee
--- /dev/null
+++ b/src/lib/Twig/Components/Chip.php
@@ -0,0 +1,51 @@
+ $props
+ *
+ * @return array
+ */
+ #[PreMount]
+ public function validate(array $props): array
+ {
+ $resolver = new OptionsResolver();
+ $resolver->setIgnoreUndefined();
+ $resolver
+ ->define('error')
+ ->allowedTypes('bool')
+ ->default(false);
+ $resolver
+ ->define('isDeletable')
+ ->allowedTypes('bool')
+ ->default(true);
+ $resolver
+ ->define('disabled')
+ ->allowedTypes('bool')
+ ->default(false);
+
+ return $resolver->resolve($props) + $props;
+ }
+}