diff --git a/.changeset/four-ghosts-change.md b/.changeset/four-ghosts-change.md
new file mode 100644
index 000000000..a53893006
--- /dev/null
+++ b/.changeset/four-ghosts-change.md
@@ -0,0 +1,5 @@
+---
+'@lion/progress-indicator': minor
+---
+
+Initial release
diff --git a/packages/progress-indicator/README.md b/packages/progress-indicator/README.md
new file mode 100644
index 000000000..ae1e8e5ad
--- /dev/null
+++ b/packages/progress-indicator/README.md
@@ -0,0 +1,90 @@
+[//]: # 'AUTO INSERT HEADER PREPUBLISH'
+
+# Progress Indicator
+
+`lion-progress-indicator` implements accessibility requirements for progress indicators.
+
+```js script
+import { html } from 'lit-html';
+import './demo/custom-progress-indicator.js';
+
+export default {
+ title: 'Others/Progress Indicator',
+};
+```
+
+## Features
+
+- Accessibility compliant
+- Localized "Loading" label
+- Implementation independent of visuals
+
+## How to use
+
+### Installation
+
+```bash
+npm i --save @lion/progress-indicator
+```
+
+```js
+import { LionProgressIndicator } from '@lion/progress-indicator';
+// or
+import '@lion/progress-indicator/lion-progress-indicator.js';
+```
+
+### Example
+
+```html
+
+```
+
+## Extended indicator with a custom visual
+
+`LionProgressIndicator` is designed to be extended to add visuals. Implement the `_graphicTemplate` method to set the rendered content, and apply styles normally.
+
+### Example extension
+
+```js
+class CustomProgressIndicator extends LionProgressIndicator {
+ static get styles() {
+ return [
+ css`
+ svg {
+ animation: spinner-rotate 2s linear infinite;
+ display: inline-block;
+ height: 48px;
+ width: 48px;
+ }
+
+ circle {
+ fill: none;
+ stroke-width: 3.6;
+ stroke: firebrick;
+ stroke-dasharray: 100, 28;
+ }
+
+ @keyframes spinner-rotate {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+ `,
+ ];
+ }
+
+ _graphicTemplate() {
+ return html``;
+ }
+}
+```
+
+### Result
+
+```js preview-story
+export const customProgressDemo = () => html`
+
+`;
+```
diff --git a/packages/progress-indicator/demo/CustomProgressIndicator.js b/packages/progress-indicator/demo/CustomProgressIndicator.js
new file mode 100644
index 000000000..85fc4d1c5
--- /dev/null
+++ b/packages/progress-indicator/demo/CustomProgressIndicator.js
@@ -0,0 +1,56 @@
+import { svg, css } from '@lion/core';
+import { LionProgressIndicator } from '../index.js';
+
+export class CustomProgressIndicator extends LionProgressIndicator {
+ static get styles() {
+ return [
+ css`
+ :host {
+ display: inline-block;
+ }
+
+ svg {
+ animation: spinner-rotate 2s linear infinite;
+ display: inline-block;
+ height: 48px;
+ width: 48px;
+ }
+
+ circle {
+ animation: spinner-dash 1.35s ease-in-out infinite;
+ fill: none;
+ stroke-width: 3.6;
+ stroke: firebrick;
+ stroke-dasharray: 100, 28; /* This is a fallback for IE11 */
+ }
+
+ @keyframes spinner-rotate {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+
+ @keyframes spinner-dash {
+ 0% {
+ stroke-dasharray: 6, 122;
+ stroke-dashoffset: 0;
+ }
+ 50% {
+ stroke-dasharray: 100, 28;
+ stroke-dashoffset: -16;
+ }
+ 100% {
+ stroke-dasharray: 6, 122;
+ stroke-dashoffset: -127;
+ }
+ }
+ `,
+ ];
+ }
+
+ _graphicTemplate() {
+ return svg``;
+ }
+}
diff --git a/packages/progress-indicator/demo/custom-progress-indicator.js b/packages/progress-indicator/demo/custom-progress-indicator.js
new file mode 100644
index 000000000..a8079806b
--- /dev/null
+++ b/packages/progress-indicator/demo/custom-progress-indicator.js
@@ -0,0 +1,3 @@
+import { CustomProgressIndicator } from './CustomProgressIndicator.js';
+
+customElements.define('custom-progress-indicator', CustomProgressIndicator);
diff --git a/packages/progress-indicator/index.js b/packages/progress-indicator/index.js
new file mode 100644
index 000000000..851df3d26
--- /dev/null
+++ b/packages/progress-indicator/index.js
@@ -0,0 +1 @@
+export { LionProgressIndicator } from './src/LionProgressIndicator.js';
diff --git a/packages/progress-indicator/lion-progress-indicator.js b/packages/progress-indicator/lion-progress-indicator.js
new file mode 100644
index 000000000..81977b6d2
--- /dev/null
+++ b/packages/progress-indicator/lion-progress-indicator.js
@@ -0,0 +1,3 @@
+import { LionProgressIndicator } from './src/LionProgressIndicator.js';
+
+customElements.define('lion-progress-indicator', LionProgressIndicator);
diff --git a/packages/progress-indicator/package.json b/packages/progress-indicator/package.json
new file mode 100644
index 000000000..c54e129ee
--- /dev/null
+++ b/packages/progress-indicator/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@lion/progress-indicator",
+ "version": "0.0.0",
+ "description": "A progress indicator that is easily styleable and accessible in all contexts",
+ "license": "MIT",
+ "author": "ing-bank",
+ "homepage": "https://github.com/ing-bank/lion/",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ing-bank/lion.git",
+ "directory": "packages/progress-indicator"
+ },
+ "main": "index.js",
+ "module": "index.js",
+ "files": [
+ "*.d.ts",
+ "*.js",
+ "src",
+ "test",
+ "translations",
+ "types"
+ ],
+ "scripts": {
+ "prepublishOnly": "../../scripts/npm-prepublish.js",
+ "start": "cd ../../ && yarn dev-server --open packages/progress-indicator/README.md",
+ "test": "cd ../../ && yarn test:browser --grep \"packages/progress-indicator/test/**/*.test.js\"",
+ "test:watch": "cd ../../ && yarn test:browser:watch --grep \"packages/progress-indicator/test/**/*.test.js\""
+ },
+ "sideEffects": [
+ "lion-progress-indicator.js"
+ ],
+ "dependencies": {
+ "@lion/core": "0.8.0",
+ "@lion/localize": "0.13.1"
+ },
+ "keywords": [
+ "lion",
+ "loading-indicator",
+ "progress-indicator",
+ "spinner",
+ "web-components"
+ ],
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/progress-indicator/src/LionProgressIndicator.js b/packages/progress-indicator/src/LionProgressIndicator.js
new file mode 100644
index 000000000..e8f89a15a
--- /dev/null
+++ b/packages/progress-indicator/src/LionProgressIndicator.js
@@ -0,0 +1,88 @@
+/* eslint-disable class-methods-use-this */
+
+import { nothing, LitElement } from '@lion/core';
+import { localize, LocalizeMixin } from '@lion/localize';
+
+export class LionProgressIndicator extends LocalizeMixin(LitElement) {
+ static get localizeNamespaces() {
+ return [
+ {
+ 'lion-progress-indicator': locale => {
+ switch (locale) {
+ case 'bg-BG':
+ case 'bg':
+ return import('../translations/bg.js');
+ case 'cs-CZ':
+ case 'cs':
+ return import('../translations/cs.js');
+ case 'de-DE':
+ case 'de':
+ return import('../translations/de.js');
+ case 'en-AU':
+ case 'en-GB':
+ case 'en-US':
+ case 'en-PH':
+ case 'en':
+ return import('../translations/en.js');
+ case 'es-ES':
+ case 'es':
+ return import('../translations/es.js');
+ case 'fr-BE':
+ case 'fr-FR':
+ case 'fr':
+ return import('../translations/fr.js');
+ case 'hu-HU':
+ case 'hu':
+ return import('../translations/hu.js');
+ case 'it-IT':
+ case 'it':
+ return import('../translations/it.js');
+ case 'nl-BE':
+ case 'nl-NL':
+ case 'nl':
+ return import('../translations/nl.js');
+ case 'pl-PL':
+ case 'pl':
+ return import('../translations/pl.js');
+ case 'ro-RO':
+ case 'ro':
+ return import('../translations/ro.js');
+ case 'ru-RU':
+ case 'ru':
+ return import('../translations/ru.js');
+ case 'sk-SK':
+ case 'sk':
+ return import('./translations/sk.js');
+ case 'uk-UA':
+ case 'uk':
+ return import('../translations/uk.js');
+ case 'zh-CN':
+ case 'zh':
+ return import('../translations/zh.js');
+ default:
+ return import('../translations/en.js');
+ }
+ },
+ },
+ ];
+ }
+
+ _graphicTemplate() {
+ return nothing;
+ }
+
+ render() {
+ return this._graphicTemplate();
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this.setAttribute('role', 'status');
+ this.setAttribute('aria-live', 'polite');
+ }
+
+ onLocaleUpdated() {
+ const label = localize.msg('lion-progress-indicator:loading');
+ this.setAttribute('aria-label', label);
+ }
+}
diff --git a/packages/progress-indicator/test/lion-progress-indicator.test.js b/packages/progress-indicator/test/lion-progress-indicator.test.js
new file mode 100644
index 000000000..e92798e56
--- /dev/null
+++ b/packages/progress-indicator/test/lion-progress-indicator.test.js
@@ -0,0 +1,23 @@
+import { expect, fixture } from '@open-wc/testing';
+import { html } from '@lion/core';
+
+import '../lion-progress-indicator.js';
+
+describe('lion-progress-indicator', () => {
+ describe('Accessibility', () => {
+ it('adds a label', async () => {
+ const el = await fixture(html` `);
+ expect(el.getAttribute('aria-label')).to.equal('Loading');
+ });
+
+ it('sets the right role', async () => {
+ const el = await fixture(html` `);
+ expect(el.getAttribute('role')).to.equal('status');
+ });
+
+ it('sets aria-live to "polite"', async () => {
+ const el = await fixture(html` `);
+ expect(el.getAttribute('aria-live')).to.equal('polite');
+ });
+ });
+});
diff --git a/packages/progress-indicator/translations/bg.js b/packages/progress-indicator/translations/bg.js
new file mode 100644
index 000000000..1aae3649c
--- /dev/null
+++ b/packages/progress-indicator/translations/bg.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Зареждане',
+};
diff --git a/packages/progress-indicator/translations/cs.js b/packages/progress-indicator/translations/cs.js
new file mode 100644
index 000000000..2750a1315
--- /dev/null
+++ b/packages/progress-indicator/translations/cs.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Načítání',
+};
diff --git a/packages/progress-indicator/translations/de.js b/packages/progress-indicator/translations/de.js
new file mode 100644
index 000000000..ec1bad6bf
--- /dev/null
+++ b/packages/progress-indicator/translations/de.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Wird geladen',
+};
diff --git a/packages/progress-indicator/translations/en.js b/packages/progress-indicator/translations/en.js
new file mode 100644
index 000000000..ad6168eaa
--- /dev/null
+++ b/packages/progress-indicator/translations/en.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Loading',
+};
diff --git a/packages/progress-indicator/translations/es.js b/packages/progress-indicator/translations/es.js
new file mode 100644
index 000000000..902f7389d
--- /dev/null
+++ b/packages/progress-indicator/translations/es.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Cargando',
+};
diff --git a/packages/progress-indicator/translations/fr.js b/packages/progress-indicator/translations/fr.js
new file mode 100644
index 000000000..380402186
--- /dev/null
+++ b/packages/progress-indicator/translations/fr.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Chargement',
+};
diff --git a/packages/progress-indicator/translations/hu.js b/packages/progress-indicator/translations/hu.js
new file mode 100644
index 000000000..90f637de3
--- /dev/null
+++ b/packages/progress-indicator/translations/hu.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Betöltés',
+};
diff --git a/packages/progress-indicator/translations/it.js b/packages/progress-indicator/translations/it.js
new file mode 100644
index 000000000..9de48d3da
--- /dev/null
+++ b/packages/progress-indicator/translations/it.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Caricamento in corso',
+};
diff --git a/packages/progress-indicator/translations/nl.js b/packages/progress-indicator/translations/nl.js
new file mode 100644
index 000000000..bf4b0d5fc
--- /dev/null
+++ b/packages/progress-indicator/translations/nl.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Laden',
+};
diff --git a/packages/progress-indicator/translations/pl.js b/packages/progress-indicator/translations/pl.js
new file mode 100644
index 000000000..15c638ca6
--- /dev/null
+++ b/packages/progress-indicator/translations/pl.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Ładuję',
+};
diff --git a/packages/progress-indicator/translations/ro.js b/packages/progress-indicator/translations/ro.js
new file mode 100644
index 000000000..b2656aa3b
--- /dev/null
+++ b/packages/progress-indicator/translations/ro.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'Se incarca',
+};
diff --git a/packages/progress-indicator/translations/ru.js b/packages/progress-indicator/translations/ru.js
new file mode 100644
index 000000000..d0f354099
--- /dev/null
+++ b/packages/progress-indicator/translations/ru.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'погрузка',
+};
diff --git a/packages/progress-indicator/translations/sk.js b/packages/progress-indicator/translations/sk.js
new file mode 100644
index 000000000..d0f354099
--- /dev/null
+++ b/packages/progress-indicator/translations/sk.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'погрузка',
+};
diff --git a/packages/progress-indicator/translations/uk.js b/packages/progress-indicator/translations/uk.js
new file mode 100644
index 000000000..5aabcd125
--- /dev/null
+++ b/packages/progress-indicator/translations/uk.js
@@ -0,0 +1,3 @@
+export default {
+ loading: 'завантаження',
+};
diff --git a/packages/progress-indicator/translations/zh.js b/packages/progress-indicator/translations/zh.js
new file mode 100644
index 000000000..2e6008fa5
--- /dev/null
+++ b/packages/progress-indicator/translations/zh.js
@@ -0,0 +1,3 @@
+export default {
+ loading: '载入中',
+};