diff --git a/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.spec.ts b/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.spec.ts
new file mode 100644
index 00000000..9170f01c
--- /dev/null
+++ b/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.spec.ts
@@ -0,0 +1,125 @@
+import { Component } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { tb_base } from '../../../../test';
+import { ItGapDirective, ItGapXDirective, ItGapYDirective } from './gap.directive';
+
+@Component({
+ selector: 'it-test-gap0',
+ standalone: true,
+ imports: [ItGapDirective],
+ template: `
content
`,
+})
+class Gap0Host {}
+
+@Component({
+ selector: 'it-test-gap1',
+ standalone: true,
+ imports: [ItGapDirective],
+ template: `content
`,
+})
+class Gap1Host {}
+
+@Component({
+ selector: 'it-test-gap3',
+ standalone: true,
+ imports: [ItGapDirective],
+ template: `content
`,
+})
+class Gap3Host {}
+
+@Component({
+ selector: 'it-test-gap5',
+ standalone: true,
+ imports: [ItGapDirective],
+ template: `content
`,
+})
+class Gap5Host {}
+
+@Component({
+ selector: 'it-test-gx2',
+ standalone: true,
+ imports: [ItGapXDirective],
+ template: `content
`,
+})
+class GapX2Host {}
+
+@Component({
+ selector: 'it-test-gy4',
+ standalone: true,
+ imports: [ItGapYDirective],
+ template: `content
`,
+})
+class GapY4Host {}
+
+@Component({
+ selector: 'it-test-combined',
+ standalone: true,
+ imports: [ItGapXDirective, ItGapYDirective],
+ template: `content
`,
+})
+class CombinedHost {}
+
+describe('ItGapDirective', () => {
+ it('should apply gap: 0 for scale 0', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap0Host] });
+ const fix = TestBed.createComponent(Gap0Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.gap).toBe('0px');
+ });
+
+ it('should apply gap: 0.25rem for scale 1', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap1Host] });
+ const fix = TestBed.createComponent(Gap1Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.gap).toBe('0.25rem');
+ });
+
+ it('should apply gap: 1rem for scale 3', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap3Host] });
+ const fix = TestBed.createComponent(Gap3Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.gap).toBe('1rem');
+ });
+
+ it('should apply gap: 3rem for scale 5', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), Gap5Host] });
+ const fix = TestBed.createComponent(Gap5Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.gap).toBe('3rem');
+ });
+});
+
+describe('ItGapXDirective', () => {
+ it('should apply column-gap: 0.5rem for scale 2', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), GapX2Host] });
+ const fix = TestBed.createComponent(GapX2Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.columnGap).toBe('0.5rem');
+ });
+});
+
+describe('ItGapYDirective', () => {
+ it('should apply row-gap: 1.5rem for scale 4', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), GapY4Host] });
+ const fix = TestBed.createComponent(GapY4Host);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.rowGap).toBe('1.5rem');
+ });
+});
+
+describe('ItGapX + ItGapY combined', () => {
+ it('should apply column-gap and row-gap independently', () => {
+ TestBed.configureTestingModule({ ...tb_base, imports: [...(tb_base.imports || []), CombinedHost] });
+ const fix = TestBed.createComponent(CombinedHost);
+ fix.detectChanges();
+ const div = fix.nativeElement.querySelector('div') as HTMLDivElement;
+ expect(div.style.columnGap).toBe('0.5rem');
+ expect(div.style.rowGap).toBe('1.5rem');
+ });
+});
diff --git a/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.ts b/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.ts
new file mode 100644
index 00000000..36d8d949
--- /dev/null
+++ b/projects/design-angular-kit/src/lib/components/utils/gap/gap.directive.ts
@@ -0,0 +1,83 @@
+import { Directive, HostBinding, Input } from '@angular/core';
+
+/** Bootstrap Italia spacer scale (0-5). */
+export type GapScale = 0 | 1 | 2 | 3 | 4 | 5;
+
+/**
+ * Maps Bootstrap Italia spacer scale values (0-5) to their actual
+ * CSS sizes following the $spacer variable ($spacer = 1rem = 16px).
+ */
+const SPACER_MAP: Record = {
+ 0: '0',
+ 1: '0.25rem',
+ 2: '0.5rem',
+ 3: '1rem',
+ 4: '1.5rem',
+ 5: '3rem',
+};
+
+/**
+ * Directive that applies the CSS `gap` property to the host element.
+ *
+ * Bootstrap Italia's `.g-*` classes only set CSS variables consumed by `.row`.
+ * This directive applies real CSS `gap`, making it usable on any flex or grid container.
+ *
+ * @example
+ * ```html
+ * ...
+ * ```
+ */
+@Directive({
+ selector: '[itGap]',
+ standalone: true,
+})
+export class ItGapDirective {
+ @Input('itGap') value: GapScale = 0;
+
+ @HostBinding('style.gap')
+ get gap(): string {
+ return SPACER_MAP[this.value] ?? '0';
+ }
+}
+
+/**
+ * Directive that applies the CSS `column-gap` property to the host element.
+ *
+ * @example
+ * ```html
+ * ...
+ * ```
+ */
+@Directive({
+ selector: '[itGapX]',
+ standalone: true,
+})
+export class ItGapXDirective {
+ @Input('itGapX') value: GapScale = 0;
+
+ @HostBinding('style.column-gap')
+ get columnGap(): string {
+ return SPACER_MAP[this.value] ?? '0';
+ }
+}
+
+/**
+ * Directive that applies the CSS `row-gap` property to the host element.
+ *
+ * @example
+ * ```html
+ * ...
+ * ```
+ */
+@Directive({
+ selector: '[itGapY]',
+ standalone: true,
+})
+export class ItGapYDirective {
+ @Input('itGapY') value: GapScale = 0;
+
+ @HostBinding('style.row-gap')
+ get rowGap(): string {
+ return SPACER_MAP[this.value] ?? '0';
+ }
+}
diff --git a/projects/design-angular-kit/src/public_api.ts b/projects/design-angular-kit/src/public_api.ts
index 344db7a6..b19f8ccd 100644
--- a/projects/design-angular-kit/src/public_api.ts
+++ b/projects/design-angular-kit/src/public_api.ts
@@ -123,6 +123,7 @@ export * from './lib/components/navigation/skiplink/skiplink/skiplink.component'
export * from './lib/components/utils/error-page/error-page.component';
export * from './lib/components/utils/icon/icon.component';
export * from './lib/components/utils/language-switcher/language-switcher.component';
+export * from './lib/components/utils/gap/gap.directive';
// Services
export * from './lib/services/notification/notification.service';