diff --git a/docs/README.md b/docs/README.md
index 9828579e23..a3fb7ce0d4 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -81,10 +81,11 @@ for more information about installing and using the source code.
A collection of Angular components for generic use.
-| Name | Description |
-|-----------------------------------------------|------------------------------|
-| [Avatar](core/components/avatar.component.md) | Displays user avatars. |
-| [Button](core/components/button.component.md) | A standard button component. |
+| Name | Description |
+|---------------------------------------------------|------------------------------|
+| [Avatar](core/components/avatar.component.md) | Displays user avatars. |
+| [Button](core/components/button.component.md) | A standard button component. |
+| [Progress](core/components/progress.component.md) | A progress bar component. |
### Components
diff --git a/docs/core/components/progress.component.md b/docs/core/components/progress.component.md
new file mode 120000
index 0000000000..db78ceb2dc
--- /dev/null
+++ b/docs/core/components/progress.component.md
@@ -0,0 +1 @@
+../../../lib/core/src/lib/progress/progress.component.md
\ No newline at end of file
diff --git a/lib/core/src/lib/progress/progress.component.html b/lib/core/src/lib/progress/progress.component.html
new file mode 100644
index 0000000000..89de51e3d6
--- /dev/null
+++ b/lib/core/src/lib/progress/progress.component.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/core/src/lib/progress/progress.component.md b/lib/core/src/lib/progress/progress.component.md
new file mode 100644
index 0000000000..333cefcdbd
--- /dev/null
+++ b/lib/core/src/lib/progress/progress.component.md
@@ -0,0 +1,79 @@
+# Progress Component
+
+`standalone`, `component`
+
+The Progress component is a simple component that can be used to display progress bars.
+
+## Usage
+
+```html
+
+```
+
+### Variant
+
+The progress bar supports the following variants:
+
+- bar (default)
+- spinner
+
+```html
+
+
+```
+
+### Mode
+
+The progress bar supports the following modes:
+
+- For progress spinner, the mode can be either `indeterminate` or `determinate`.
+- For progress bar, the mode can be either `determinate`, `indeterminate`, `buffer`, or `query`.
+
+> For the spinner variant, setting the mode to unsupported values will default to `indeterminate`.
+
+Example:
+
+```html
+
+
+```
+
+### Color
+
+The progress bar supports the following colors:
+
+- default
+- primary
+- accent
+- warn
+
+```html
+
+
+
+```
+
+## API
+
+Import the following standalone components:
+
+```typescript
+import { ProgressComponent } from '@alfresco/adf-core';
+```
+
+## Properties
+
+| Name | Type | Default | Description |
+|-----------|-----------------|-----------------|-----------------------------------------------------------|
+| `variant` | ProgressVariant | `bar` | The progress bar variant. |
+| `value` | number | | The value of the progress bar. |
+| `color` | ProgressColor | | The color of the progress bar. |
+| `mode` | ProgressMode | `indeterminate` | The mode of the progress bar. |
+| `testId` | string | | The button test id (uses `data-automation-id` attribute). |
+
+### Accessibility
+
+The button component has been designed to be accessible. The following attributes are available:
+
+- `ariaLabel`: The button aria label.
+- `ariaHidden`: Whether the button should be hidden from the accessibility tree.
diff --git a/lib/core/src/lib/progress/progress.component.spec.ts b/lib/core/src/lib/progress/progress.component.spec.ts
new file mode 100644
index 0000000000..f65046b7e1
--- /dev/null
+++ b/lib/core/src/lib/progress/progress.component.spec.ts
@@ -0,0 +1,103 @@
+/*!
+ * @license
+ * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { HarnessLoader } from '@angular/cdk/testing';
+import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
+import { MatProgressBarHarness } from '@angular/material/progress-bar/testing';
+import { ProgressComponent } from './progress.component';
+
+describe('ProgressComponent', () => {
+ let component: ProgressComponent;
+ let fixture: ComponentFixture;
+ let loader: HarnessLoader;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [MatProgressBarModule, MatProgressSpinnerModule, NoopAnimationsModule, ProgressComponent]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(ProgressComponent);
+ loader = TestbedHarnessEnvironment.loader(fixture);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should default to bar variant and indeterminate mode', () => {
+ expect(component.variant).toBe('bar');
+ expect(component.mode).toBe('indeterminate');
+ });
+
+ it('should change mode to determinate when value is set', () => {
+ component.value = 50;
+ expect(component.mode).toBe('determinate');
+ });
+
+ it('should not change mode if variant is spinner and an invalid mode is set', () => {
+ component.variant = 'spinner';
+ component.mode = 'query'; // Invalid for spinner
+ expect(component.mode).toBe('indeterminate');
+ });
+
+ it('should accept buffer mode when variant is bar', () => {
+ component.variant = 'bar';
+ component.mode = 'buffer';
+ expect(component.mode).toBe('buffer');
+ });
+
+ it('should ignore setting value to undefined', () => {
+ component.value = 50;
+ component.value = undefined;
+ expect(component.value).toBeUndefined();
+ expect(component.mode).toBe('determinate'); // Mode remains unchanged
+ });
+
+ it('should apply ariaLabel if provided', async () => {
+ const testLabel = 'Progress Label';
+ component.ariaLabel = testLabel;
+ fixture.detectChanges();
+
+ const progress = await loader.getHarness(MatProgressBarHarness);
+ const host = await progress.host();
+ expect(await host.getAttribute('aria-label')).toBe(testLabel);
+ });
+
+ it('should hide from accessibility tree if ariaHidden is true', async () => {
+ component.ariaHidden = true;
+ fixture.detectChanges();
+
+ const progress = await loader.getHarness(MatProgressBarHarness);
+ const host = await progress.host();
+
+ expect(await host.getAttribute('aria-hidden')).toBe('true');
+ });
+
+ it('should set testId if provided', () => {
+ const testId = 'progress-test-id';
+ component.testId = testId;
+ fixture.detectChanges();
+ const progressBarElement = fixture.nativeElement.querySelector(`[data-automation-id="${testId}"]`);
+ expect(progressBarElement).not.toBeNull();
+ });
+});
diff --git a/lib/core/src/lib/progress/progress.component.ts b/lib/core/src/lib/progress/progress.component.ts
new file mode 100644
index 0000000000..4aee682118
--- /dev/null
+++ b/lib/core/src/lib/progress/progress.component.ts
@@ -0,0 +1,87 @@
+/*!
+ * @license
+ * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Component, Input, ViewEncapsulation } from '@angular/core';
+import { MatProgressBarModule, ProgressBarMode } from '@angular/material/progress-bar';
+import { MatProgressSpinnerModule, ProgressSpinnerMode } from '@angular/material/progress-spinner';
+import { CommonModule } from '@angular/common';
+import { ThemePalette } from '@angular/material/core';
+
+export type ProgressVariant = 'bar' | 'spinner' | undefined;
+export type ProgressMode = ProgressBarMode | ProgressSpinnerMode;
+export type ProgressColor = ThemePalette;
+
+@Component({
+ selector: 'adf-progress',
+ standalone: true,
+ imports: [CommonModule, MatProgressBarModule, MatProgressSpinnerModule],
+ templateUrl: './progress.component.html',
+ encapsulation: ViewEncapsulation.None
+})
+export class ProgressComponent {
+ private _mode: ProgressMode = 'indeterminate';
+ private _value?: number;
+
+ @Input() variant: ProgressVariant = 'bar';
+ @Input() color?: ProgressColor;
+ @Input() ariaLabel?: string;
+ @Input() ariaHidden?: boolean;
+ @Input() testId?: string;
+
+ /**
+ * The value of the progress bar or spinner.
+ * Changes the mode to `determinate` if a value is provided.
+ *
+ * @returns The progress value
+ */
+ get value(): number | undefined {
+ return this._value;
+ }
+
+ @Input()
+ set value(value: number | undefined) {
+ if (value !== undefined) {
+ this._mode = 'determinate';
+ }
+ this._value = value;
+ }
+
+ /**
+ * The progress bar display mode. Defaults to `indeterminate`.
+ *
+ * For progress spinner, the mode can be either `indeterminate` or `determinate`.
+ * For progress bar, the mode can be either `determinate`, `indeterminate`, `buffer`, or `query`.
+ *
+ * @returns The progress mode
+ */
+ get mode(): ProgressMode {
+ return this._mode;
+ }
+
+ @Input()
+ set mode(value: ProgressMode) {
+ if (this.variant === 'spinner') {
+ if (value === 'indeterminate' || value === 'determinate') {
+ this._mode = value;
+ } else {
+ this._mode = 'indeterminate';
+ }
+ } else {
+ this._mode = value;
+ }
+ }
+}
diff --git a/lib/core/src/public-api.ts b/lib/core/src/public-api.ts
index 84ce1ca93f..6c2bf9d0c8 100644
--- a/lib/core/src/public-api.ts
+++ b/lib/core/src/public-api.ts
@@ -18,6 +18,7 @@
export * from './lib/about/index';
export * from './lib/avatar/avatar.component';
export * from './lib/button/button.component';
+export * from './lib/progress/progress.component';
export * from './lib/viewer/index';
export * from './lib/toolbar/index';
export * from './lib/pagination/index';