diff --git a/projects/cps-ui-kit/src/lib/components/cps-input/cps-input.component.html b/projects/cps-ui-kit/src/lib/components/cps-input/cps-input.component.html
index 2e083ea00..50dbaf677 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-input/cps-input.component.html
+++ b/projects/cps-ui-kit/src/lib/components/cps-input/cps-input.component.html
@@ -141,8 +141,8 @@
}
@if (loading) {
diff --git a/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.html b/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.html
index e2cae6e79..54ab2d2cf 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.html
+++ b/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.html
@@ -1,4 +1,5 @@
{
);
expect(indicator).toBeTruthy();
});
+
+ it('should have role="progressbar" on the host element', () => {
+ expect(fixture.nativeElement.getAttribute('role')).toBe('progressbar');
+ });
+
+ it('should have default aria-label "Loading" on the host element', () => {
+ expect(fixture.nativeElement.getAttribute('aria-label')).toBe('Loading');
+ });
+
+ it('should reflect a custom ariaLabel on the host element', () => {
+ fixture.componentRef.setInput('ariaLabel', 'Uploading file');
+ fixture.detectChanges();
+ expect(fixture.nativeElement.getAttribute('aria-label')).toBe(
+ 'Uploading file'
+ );
+ });
+
+ it('should use a native aria-label attribute as the accessible label', () => {
+ const host: HTMLElement = fixture.nativeElement;
+ host.setAttribute('aria-label', 'Saving changes');
+ fixture.detectChanges();
+ expect(host.getAttribute('aria-label')).toBe('Saving changes');
+ });
+
+ it('should mark the inner wrapper div as aria-hidden', () => {
+ const wrapper = fixture.nativeElement.querySelector('.cps-progress-linear');
+ expect(wrapper.getAttribute('aria-hidden')).toBe('true');
+ });
});
diff --git a/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.ts b/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.ts
index 16b1de9f8..e0d785c02 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.ts
+++ b/projects/cps-ui-kit/src/lib/components/cps-progress-linear/cps-progress-linear.component.ts
@@ -1,5 +1,15 @@
import { DOCUMENT } from '@angular/common';
-import { Component, computed, inject, input } from '@angular/core';
+import {
+ Component,
+ ElementRef,
+ HostAttributeToken,
+ Renderer2,
+ afterNextRender,
+ computed,
+ effect,
+ inject,
+ input
+} from '@angular/core';
import { getCSSColor } from '../../utils/colors-utils';
import { convertSize } from '../../utils/internal/size-utils';
@@ -10,7 +20,10 @@ import { convertSize } from '../../utils/internal/size-utils';
@Component({
selector: 'cps-progress-linear',
templateUrl: './cps-progress-linear.component.html',
- styleUrls: ['./cps-progress-linear.component.scss']
+ styleUrls: ['./cps-progress-linear.component.scss'],
+ host: {
+ role: 'progressbar'
+ }
})
export class CpsProgressLinearComponent {
/**
@@ -55,11 +68,48 @@ export class CpsProgressLinearComponent {
*/
radius = input(0);
- private readonly document = inject(DOCUMENT);
+ /**
+ * Accessible label announced by screen readers to describe what is loading.
+ * Falls back to "Loading" when empty value is provided.
+ * @group Props
+ * @default Loading
+ */
+ ariaLabel = input('');
+
+ private readonly _elementRef = inject(ElementRef);
+ private readonly _document = inject(DOCUMENT);
+ private readonly _renderer = inject(Renderer2);
+ private readonly _staticAriaLabel = inject(
+ new HostAttributeToken('aria-label'),
+ { optional: true }
+ );
cvtWidth = computed(() => convertSize(this.width()));
cvtHeight = computed(() => convertSize(this.height()));
cvtRadius = computed(() => convertSize(this.radius()));
- cssColor = computed(() => getCSSColor(this.color(), this.document));
- cssBgColor = computed(() => getCSSColor(this.bgColor(), this.document));
+ cssColor = computed(() => getCSSColor(this.color(), this._document));
+ cssBgColor = computed(() => getCSSColor(this.bgColor(), this._document));
+
+ constructor() {
+ effect(() => {
+ const label = this.ariaLabel() || this._staticAriaLabel;
+ if (label) {
+ this._renderer.setAttribute(
+ this._elementRef.nativeElement,
+ 'aria-label',
+ label
+ );
+ }
+ });
+
+ afterNextRender(() => {
+ if (!this._elementRef.nativeElement.getAttribute('aria-label')) {
+ this._renderer.setAttribute(
+ this._elementRef.nativeElement,
+ 'aria-label',
+ 'Loading'
+ );
+ }
+ });
+ }
}
diff --git a/projects/cps-ui-kit/src/lib/components/cps-select/cps-select.component.html b/projects/cps-ui-kit/src/lib/components/cps-select/cps-select.component.html
index a0347a0fe..cfa92ebf0 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-select/cps-select.component.html
+++ b/projects/cps-ui-kit/src/lib/components/cps-select/cps-select.component.html
@@ -226,8 +226,8 @@
@if (loading) {
diff --git a/projects/cps-ui-kit/src/lib/components/cps-tree-autocomplete/cps-tree-autocomplete.component.html b/projects/cps-ui-kit/src/lib/components/cps-tree-autocomplete/cps-tree-autocomplete.component.html
index c1a437a15..ac6d4c526 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-tree-autocomplete/cps-tree-autocomplete.component.html
+++ b/projects/cps-ui-kit/src/lib/components/cps-tree-autocomplete/cps-tree-autocomplete.component.html
@@ -210,8 +210,8 @@
@if (loading) {
diff --git a/projects/cps-ui-kit/src/lib/components/cps-tree-select/cps-tree-select.component.html b/projects/cps-ui-kit/src/lib/components/cps-tree-select/cps-tree-select.component.html
index f14d13d75..4524438d7 100644
--- a/projects/cps-ui-kit/src/lib/components/cps-tree-select/cps-tree-select.component.html
+++ b/projects/cps-ui-kit/src/lib/components/cps-tree-select/cps-tree-select.component.html
@@ -163,8 +163,8 @@
@if (loading) {