diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1faa5a8f9..0e38f2788 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Added
+- Banner component [#1174](https://github.com/IgniteUI/igniteui-webcomponents/issues/1174)
### Fixed
- Input, Textarea - passing `undefined` to **value** sets the underlying input value to undefined [#1206](https://github.com/IgniteUI/igniteui-webcomponents/issues/1206)
diff --git a/src/components/banner/banner.spec.ts b/src/components/banner/banner.spec.ts
new file mode 100644
index 000000000..afeda6774
--- /dev/null
+++ b/src/components/banner/banner.spec.ts
@@ -0,0 +1,289 @@
+import {
+ elementUpdated,
+ expect,
+ fixture,
+ html,
+ nextFrame,
+} from '@open-wc/testing';
+import { spy } from 'sinon';
+
+import { defineComponents } from '../common/definitions/defineComponents.js';
+import { finishAnimationsFor } from '../common/utils.spec.js';
+import IgcBannerComponent from './banner.js';
+
+describe('Banner', () => {
+ before(() => {
+ defineComponents(IgcBannerComponent);
+ });
+
+ const createDefaultBanner = () => html`
+ You are currently offline.
+ `;
+
+ const createSlottedBanner = () => html`
+
+
+ Build 123 completed!
+
+ OK 1
+ View log
+
+
+ `;
+
+ let banner: IgcBannerComponent;
+
+ beforeEach(async () => {
+ banner = await fixture(createDefaultBanner());
+ });
+
+ const DIFF_OPTIONS = {
+ ignoreTags: ['igc-button'],
+ ignoreAttributes: ['inert'],
+ };
+
+ const BUTTON_DIFF_OPTIONS = ['variant', 'size', 'style'];
+
+ async function clickHideComplete() {
+ finishAnimationsFor(banner.shadowRoot!);
+ await elementUpdated(banner);
+ await nextFrame();
+ await nextFrame();
+ }
+
+ describe('Initialization Tests', () => {
+ it('passes the a11y audit', async () => {
+ await expect(banner).to.be.accessible();
+ await expect(banner).shadowDom.to.be.accessible();
+ });
+
+ it('is correctly initialized with its default component state', () => {
+ expect(banner.open).to.be.false;
+ expect(banner.dir).to.be.empty;
+ });
+
+ it('should render a default action button', () => {
+ const button = banner.shadowRoot!.querySelector('igc-button');
+
+ expect(button).not.to.be.null;
+ expect(button).dom.to.equal(`OK`, {
+ ignoreAttributes: BUTTON_DIFF_OPTIONS,
+ });
+ });
+
+ it('is correctly rendered both in shown/hidden states', async () => {
+ expect(banner.open).to.be.false;
+
+ expect(banner).dom.to.equal(
+ 'You are currently offline.'
+ );
+ expect(banner).shadowDom.to.equal(
+ ``,
+ {
+ ignoreAttributes: BUTTON_DIFF_OPTIONS,
+ }
+ );
+
+ await banner.show();
+
+ expect(banner).dom.to.equal(
+ 'You are currently offline.'
+ );
+ expect(banner).shadowDom.to.equal(
+ ``,
+ {
+ ignoreAttributes: BUTTON_DIFF_OPTIONS,
+ }
+ );
+ });
+
+ it('should correctly render slotted content', async () => {
+ banner = await fixture(createSlottedBanner());
+
+ const prefix = banner.querySelector('igc-icon');
+ const actions = banner.querySelector('div');
+
+ expect(prefix).not.to.be.null;
+ expect(actions).not.to.be.null;
+
+ expect(actions?.children[0]).dom.to.equal(
+ 'OK 1',
+ {
+ ignoreAttributes: [...BUTTON_DIFF_OPTIONS, 'type'],
+ }
+ );
+
+ expect(actions?.children[1]).dom.to.equal(
+ 'View log',
+ {
+ ignoreAttributes: [...BUTTON_DIFF_OPTIONS, 'type'],
+ }
+ );
+ });
+ });
+
+ describe('Methods` Tests', () => {
+ it('calls `show` and `hide` methods successfully', async () => {
+ expect(banner.open).to.be.false;
+
+ await banner.show();
+
+ expect(banner.open).to.be.true;
+ expect(banner).dom.to.equal(
+ 'You are currently offline.',
+ DIFF_OPTIONS
+ );
+
+ await banner.hide();
+
+ expect(banner.open).to.be.false;
+ expect(banner).dom.to.equal(
+ 'You are currently offline.',
+ DIFF_OPTIONS
+ );
+ });
+
+ it('calls `toggle` method successfully', async () => {
+ expect(banner.open).to.be.false;
+
+ await banner.toggle();
+
+ expect(banner.open).to.be.true;
+ expect(banner).dom.to.equal(
+ 'You are currently offline.',
+ DIFF_OPTIONS
+ );
+
+ await banner.toggle();
+
+ expect(banner.open).to.be.false;
+ expect(banner).dom.to.equal(
+ 'You are currently offline.',
+ DIFF_OPTIONS
+ );
+ });
+
+ it('`show`, `hide`, `toggle` methods return proper values', async () => {
+ expect(banner.open).to.be.false;
+
+ // hide banner when already hidden
+ let animation = await banner.hide();
+ expect(animation).to.be.false;
+
+ // show banner when hidden
+ animation = await banner.show();
+ expect(animation).to.be.true;
+ expect(banner.open).to.be.true;
+
+ // show banner when already shown
+ animation = await banner.show();
+ expect(animation).to.be.false;
+
+ // hide banner when shown
+ animation = await banner.hide();
+ expect(animation).to.be.true;
+ expect(banner.open).to.be.false;
+
+ // hide -> show
+ animation = await banner.toggle();
+ expect(animation).to.be.true;
+ expect(banner.open).to.be.true;
+
+ // show -> hide
+ animation = await banner.toggle();
+ expect(animation).to.be.true;
+ expect(banner.open).to.be.false;
+ });
+ });
+
+ describe('Action Tests', () => {
+ it('should close the banner when clicking the default button', async () => {
+ expect(banner.open).to.be.false;
+
+ await banner.show();
+
+ expect(banner.open).to.be.true;
+
+ const button = banner.shadowRoot!.querySelector('igc-button');
+
+ button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
+ await clickHideComplete();
+
+ expect(banner.open).to.be.false;
+ });
+
+ it('should emit correct event sequence for the default action button', async () => {
+ const eventSpy = spy(banner, 'emitEvent');
+
+ expect(banner.open).to.be.false;
+
+ await banner.show();
+
+ expect(banner.open).to.be.true;
+
+ const button = banner.shadowRoot!.querySelector('igc-button');
+ button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
+
+ expect(eventSpy.callCount).to.equal(1);
+ expect(eventSpy).calledWith('igcClosing', { cancelable: true });
+
+ eventSpy.resetHistory();
+ await clickHideComplete();
+
+ expect(eventSpy).calledWith('igcClosed');
+ expect(banner.open).to.be.false;
+ });
+
+ it('can cancel `igcClosing` event', async () => {
+ const eventSpy = spy(banner, 'emitEvent');
+ const button = banner.shadowRoot!.querySelector('igc-button');
+
+ banner.addEventListener('igcClosing', (event) => {
+ event.preventDefault();
+ });
+
+ await banner.show();
+
+ expect(banner.open).to.be.true;
+
+ button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
+ await clickHideComplete();
+
+ expect(eventSpy).calledWith('igcClosing');
+ expect(eventSpy).not.calledWith('igcClosed');
+ expect(banner.open).to.be.true;
+ });
+ });
+});
diff --git a/src/components/banner/banner.ts b/src/components/banner/banner.ts
new file mode 100644
index 000000000..62c7b6ef7
--- /dev/null
+++ b/src/components/banner/banner.ts
@@ -0,0 +1,148 @@
+import { LitElement, html } from 'lit';
+import { property } from 'lit/decorators.js';
+import { type Ref, createRef, ref } from 'lit/directives/ref.js';
+
+import { addAnimationController } from '../../animations/player.js';
+import { growVerIn, growVerOut } from '../../animations/presets/grow/index.js';
+import { themes } from '../../theming/theming-decorator.js';
+import IgcButtonComponent from '../button/button.js';
+import { registerComponent } from '../common/definitions/register.js';
+import type { Constructor } from '../common/mixins/constructor.js';
+import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
+import { styles } from './themes/banner.base.css.js';
+import { all } from './themes/themes.js';
+
+export interface IgcBannerComponentEventMap {
+ igcClosing: CustomEvent;
+ igcClosed: CustomEvent;
+}
+
+/**
+ * The `igc-banner` component displays important and concise message(s) for a user to address, that is specific to a page or feature.
+ *
+ * @element igc-banner
+ *
+ * @slot - Renders the text content of the banner message.
+ * @slot prefix - Renders additional content at the start of the message block.
+ * @slot actions - Renders any action elements.
+ *
+ * @fires igcClosing - Emitted before closing the banner - when a user interacts (click) with the default action of the banner.
+ * @fires igcClosed - Emitted after the banner is closed - when a user interacts (click) with the default action of the banner.
+ *
+ * @csspart base - The base wrapper of the banner component.
+ * @csspart spacer - The inner wrapper that sets the space around the banner.
+ * @csspart message - The part that holds the text and the illustration.
+ * @csspart illustration - The part that holds the banner icon/illustration.
+ * @csspart content - The part that holds the banner text content.
+ * @csspart actions - The part that holds the banner action buttons.
+ */
+
+@themes(all)
+export default class IgcBannerComponent extends EventEmitterMixin<
+ IgcBannerComponentEventMap,
+ Constructor
+>(LitElement) {
+ public static readonly tagName = 'igc-banner';
+ public static styles = [styles];
+
+ /* blazorSuppress */
+ public static register() {
+ registerComponent(IgcBannerComponent, IgcButtonComponent);
+ }
+
+ private _internals: ElementInternals;
+ private _bannerRef: Ref = createRef();
+ private _animationPlayer = addAnimationController(this, this._bannerRef);
+
+ /**
+ * Determines whether the banner is being shown/hidden.
+ * @attr
+ */
+ @property({ type: Boolean, reflect: true })
+ public open = false;
+
+ constructor() {
+ super();
+ this._internals = this.attachInternals();
+
+ this._internals.role = 'status';
+ this._internals.ariaLive = 'polite';
+ }
+
+ /** Shows the banner if not already shown. Returns `true` when the animation has completed. */
+ public async show(): Promise {
+ if (this.open) {
+ return false;
+ }
+
+ this.open = true;
+ return await this.toggleAnimation('open');
+ }
+
+ /** Hides the banner if not already hidden. Returns `true` when the animation has completed. */
+ public async hide(): Promise {
+ if (!this.open) {
+ return false;
+ }
+
+ await this.toggleAnimation('close');
+ this.open = false;
+ return true;
+ }
+
+ /** Toggles between shown/hidden state. Returns `true` when the animation has completed. */
+ public async toggle(): Promise {
+ return this.open ? await this.hide() : await this.show();
+ }
+
+ private async toggleAnimation(dir: 'open' | 'close') {
+ const animation = dir === 'open' ? growVerIn : growVerOut;
+
+ const [_, event] = await Promise.all([
+ this._animationPlayer.stopAll(),
+ this._animationPlayer.play(animation()),
+ ]);
+
+ return event.type === 'finish';
+ }
+
+ private async handleClick() {
+ if (this.emitEvent('igcClosing', { cancelable: true })) {
+ await this.hide();
+ this.emitEvent('igcClosed');
+ }
+ }
+
+ protected override render() {
+ return html`
+
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'igc-banner': IgcBannerComponent;
+ }
+}
diff --git a/src/components/banner/themes/banner.base.scss b/src/components/banner/themes/banner.base.scss
new file mode 100644
index 000000000..647fb6935
--- /dev/null
+++ b/src/components/banner/themes/banner.base.scss
@@ -0,0 +1,62 @@
+@use 'styles/utilities' as *;
+
+:host {
+ display: block;
+ min-width: rem(320px);
+ flex-basis: rem(320px);
+}
+
+[part~='spacer'] {
+ display: flex;
+ flex-wrap: wrap;
+ padding: rem(16px) rem(8px);
+ gap: rem(8px);
+ justify-content: flex-end;
+}
+
+[part~='message'] {
+ min-width: rem(150px);
+ flex-basis: rem(150px);
+ flex-grow: 1;
+}
+
+[part~='illustration'] {
+ justify-content: center;
+}
+
+[part~='illustration'],
+[part~='message'] {
+ display: flex;
+ align-items: center;
+}
+
+[part~='actions'] {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ align-items: center;
+ align-self: flex-end;
+}
+
+::slotted([slot='actions']) {
+ display: flex;
+ flex-wrap: wrap;
+ gap: rem(8px);
+}
+
+::slotted([slot='prefix']) {
+ margin-inline-end: rem(16px);
+}
+
+// OPEN CLOSE BEHAVIOR
+[part~='base'] {
+ overflow: hidden;
+}
+
+:host(:not([open])) [part~='base'] {
+ height: 0;
+}
+
+:host([open]) [part~='base'] {
+ height: auto;
+}
diff --git a/src/components/banner/themes/dark/_themes.scss b/src/components/banner/themes/dark/_themes.scss
new file mode 100644
index 000000000..785c2d135
--- /dev/null
+++ b/src/components/banner/themes/dark/_themes.scss
@@ -0,0 +1,7 @@
+@use 'styles/utilities' as *;
+@use 'igniteui-theming/sass/themes/schemas/components/dark/banner' as *;
+
+$material: digest-schema($dark-material-banner);
+$bootstrap: digest-schema($dark-bootstrap-banner);
+$fluent: digest-schema($dark-fluent-banner);
+$indigo: digest-schema($dark-indigo-banner);
diff --git a/src/components/banner/themes/dark/banner.bootstrap.scss b/src/components/banner/themes/dark/banner.bootstrap.scss
new file mode 100644
index 000000000..840363c57
--- /dev/null
+++ b/src/components/banner/themes/dark/banner.bootstrap.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $bootstrap;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/dark/banner.fluent.scss b/src/components/banner/themes/dark/banner.fluent.scss
new file mode 100644
index 000000000..4624a8067
--- /dev/null
+++ b/src/components/banner/themes/dark/banner.fluent.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $fluent;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/dark/banner.indigo.scss b/src/components/banner/themes/dark/banner.indigo.scss
new file mode 100644
index 000000000..076d232e7
--- /dev/null
+++ b/src/components/banner/themes/dark/banner.indigo.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $indigo;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/dark/banner.material.scss b/src/components/banner/themes/dark/banner.material.scss
new file mode 100644
index 000000000..a5e2f2109
--- /dev/null
+++ b/src/components/banner/themes/dark/banner.material.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $material;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/light/_themes.scss b/src/components/banner/themes/light/_themes.scss
new file mode 100644
index 000000000..070321847
--- /dev/null
+++ b/src/components/banner/themes/light/_themes.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'igniteui-theming/sass/themes/schemas/components/light/banner' as *;
+
+$base: digest-schema($light-banner);
+$material: digest-schema($material-banner);
+$bootstrap: digest-schema($bootstrap-banner);
+$fluent: digest-schema($fluent-banner);
+$indigo: digest-schema($indigo-banner);
diff --git a/src/components/banner/themes/light/banner.bootstrap.scss b/src/components/banner/themes/light/banner.bootstrap.scss
new file mode 100644
index 000000000..840363c57
--- /dev/null
+++ b/src/components/banner/themes/light/banner.bootstrap.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $bootstrap;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/light/banner.fluent.scss b/src/components/banner/themes/light/banner.fluent.scss
new file mode 100644
index 000000000..4624a8067
--- /dev/null
+++ b/src/components/banner/themes/light/banner.fluent.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $fluent;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/light/banner.indigo.scss b/src/components/banner/themes/light/banner.indigo.scss
new file mode 100644
index 000000000..076d232e7
--- /dev/null
+++ b/src/components/banner/themes/light/banner.indigo.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $indigo;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/light/banner.material.scss b/src/components/banner/themes/light/banner.material.scss
new file mode 100644
index 000000000..a5e2f2109
--- /dev/null
+++ b/src/components/banner/themes/light/banner.material.scss
@@ -0,0 +1,8 @@
+@use 'styles/utilities' as *;
+@use 'themes' as *;
+
+$theme: $material;
+
+:host {
+ @include css-vars-from-theme($theme, 'ig-banner');
+}
diff --git a/src/components/banner/themes/shared/banner.bootstrap.scss b/src/components/banner/themes/shared/banner.bootstrap.scss
new file mode 100644
index 000000000..fe7d91362
--- /dev/null
+++ b/src/components/banner/themes/shared/banner.bootstrap.scss
@@ -0,0 +1,32 @@
+@use 'styles/utilities' as *;
+@use '../light/themes' as *;
+
+$theme: $bootstrap;
+
+[part~='spacer'] {
+ background: var-get($theme, 'banner-background');
+ box-shadow: inset 0 rem(-1px) 0 0 var-get($theme, 'banner-border-color');
+ border-radius: var-get($theme, 'border-radius');
+}
+
+[part~='message'] {
+ padding: 0 rem(8px);
+}
+
+::slotted([slot='prefix']) {
+ --default-size: 3;
+ --component-size: var(--ig-size, var(--default-size)) !important;
+
+ color: inherit;
+}
+
+[part~='illustration'] {
+ color: var-get($theme, 'banner-illustration-color');
+}
+
+[part~='content'] {
+ @include type-style('body-2');
+
+ color: var-get($theme, 'banner-message-color');
+}
+
diff --git a/src/components/banner/themes/shared/banner.fluent.scss b/src/components/banner/themes/shared/banner.fluent.scss
new file mode 100644
index 000000000..35b50284d
--- /dev/null
+++ b/src/components/banner/themes/shared/banner.fluent.scss
@@ -0,0 +1,32 @@
+@use 'styles/utilities' as *;
+@use '../light/themes' as *;
+
+$theme: $fluent;
+
+[part~='spacer'] {
+ background: var-get($theme, 'banner-background');
+ box-shadow: inset 0 rem(-1px) 0 0 var-get($theme, 'banner-border-color');
+ border-radius: var-get($theme, 'border-radius');
+}
+
+[part~='message'] {
+ padding: 0 rem(8px);
+}
+
+::slotted([slot='prefix']) {
+ --default-size: 3;
+ --component-size: var(--ig-size, var(--default-size)) !important;
+
+ color: inherit;
+}
+
+[part~='illustration'] {
+ color: var-get($theme, 'banner-illustration-color');
+}
+
+[part~='content'] {
+ @include type-style('caption');
+
+ color: var-get($theme, 'banner-message-color');
+}
+
diff --git a/src/components/banner/themes/shared/banner.indigo.scss b/src/components/banner/themes/shared/banner.indigo.scss
new file mode 100644
index 000000000..9f3d4f580
--- /dev/null
+++ b/src/components/banner/themes/shared/banner.indigo.scss
@@ -0,0 +1,33 @@
+@use 'styles/utilities' as *;
+@use '../light/themes' as *;
+
+$theme: $indigo;
+
+[part~='spacer'] {
+ padding: rem(16px);
+ background: var-get($theme, 'banner-background');
+ box-shadow: inset 0 0 0 rem(1px) var-get($theme, 'banner-border-color');
+ border-radius: var-get($theme, 'border-radius');
+}
+
+[part~='message'] {
+ gap: rem(8px);
+}
+
+::slotted([slot='prefix']) {
+ --default-size: 2;
+ --component-size: var(--ig-size, var(--default-size)) !important;
+
+ margin-inline-end: 0;
+ color: inherit;
+}
+
+[part~='illustration'] {
+ color: var-get($theme, 'banner-illustration-color');
+}
+
+[part~='content'] {
+ @include type-style('body-2');
+
+ color: var-get($theme, 'banner-message-color');
+}
diff --git a/src/components/banner/themes/shared/banner.material.scss b/src/components/banner/themes/shared/banner.material.scss
new file mode 100644
index 000000000..9285ea335
--- /dev/null
+++ b/src/components/banner/themes/shared/banner.material.scss
@@ -0,0 +1,31 @@
+@use 'styles/utilities' as *;
+@use '../light/themes' as *;
+
+$theme: $material;
+
+[part~='spacer'] {
+ background: var-get($theme, 'banner-background');
+ box-shadow: inset 0 rem(-1px) 0 0 var-get($theme, 'banner-border-color');
+ border-radius: var-get($theme, 'border-radius');
+}
+
+[part~='message'] {
+ padding: 0 rem(8px);
+}
+
+::slotted([slot='prefix']) {
+ --default-size: 3;
+ --component-size: var(--ig-size, var(--default-size)) !important;
+
+ color: inherit;
+}
+
+[part~='illustration'] {
+ color: var-get($theme, 'banner-illustration-color');
+}
+
+[part~='content'] {
+ @include type-style('body-2');
+
+ color: var-get($theme, 'banner-message-color');
+}
diff --git a/src/components/banner/themes/themes.ts b/src/components/banner/themes/themes.ts
new file mode 100644
index 000000000..a2c47bc10
--- /dev/null
+++ b/src/components/banner/themes/themes.ts
@@ -0,0 +1,50 @@
+import { css } from 'lit';
+
+import type { Themes } from '../../../theming/types.js';
+// Dark Overrides
+import { styles as bootstrapDark } from './dark/banner.bootstrap.css.js';
+import { styles as fluentDark } from './dark/banner.fluent.css.js';
+import { styles as indigoDark } from './dark/banner.indigo.css.js';
+import { styles as materialDark } from './dark/banner.material.css.js';
+// Light Overrides
+import { styles as bootstrapLight } from './light/banner.bootstrap.css.js';
+import { styles as fluentLight } from './light/banner.fluent.css.js';
+import { styles as indigoLight } from './light/banner.indigo.css.js';
+import { styles as materialLight } from './light/banner.material.css.js';
+// Shared Styles
+import { styles as bootstrap } from './shared/banner.bootstrap.css.js';
+import { styles as fluent } from './shared/banner.fluent.css.js';
+import { styles as indigo } from './shared/banner.indigo.css.js';
+import { styles as material } from './shared/banner.material.css.js';
+
+const light = {
+ bootstrap: css`
+ ${bootstrap} ${bootstrapLight}
+ `,
+ material: css`
+ ${material} ${materialLight}
+ `,
+ fluent: css`
+ ${fluent} ${fluentLight}
+ `,
+ indigo: css`
+ ${indigo} ${indigoLight}
+ `,
+};
+
+const dark = {
+ bootstrap: css`
+ ${bootstrap} ${bootstrapDark}
+ `,
+ material: css`
+ ${material} ${materialDark}
+ `,
+ fluent: css`
+ ${fluent} ${fluentDark}
+ `,
+ indigo: css`
+ ${indigo} ${indigoDark}
+ `,
+};
+
+export const all: Themes = { light, dark };
diff --git a/src/components/common/definitions/defineAllComponents.ts b/src/components/common/definitions/defineAllComponents.ts
index 0284d2e72..b2e876b19 100644
--- a/src/components/common/definitions/defineAllComponents.ts
+++ b/src/components/common/definitions/defineAllComponents.ts
@@ -1,6 +1,7 @@
import IgcAccordionComponent from '../../accordion/accordion.js';
import IgcAvatarComponent from '../../avatar/avatar.js';
import IgcBadgeComponent from '../../badge/badge.js';
+import IgcBannerComponent from '../../banner/banner.js';
import IgcButtonGroupComponent from '../../button-group/button-group.js';
import IgcToggleButtonComponent from '../../button-group/toggle-button.js';
import IgcButtonComponent from '../../button/button.js';
@@ -65,6 +66,7 @@ const allComponents: IgniteComponent[] = [
IgcAvatarComponent,
IgcAccordionComponent,
IgcBadgeComponent,
+ IgcBannerComponent,
IgcButtonComponent,
IgcIconButtonComponent,
IgcToggleButtonComponent,
diff --git a/src/index.ts b/src/index.ts
index b63fdffa6..b9c83d032 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,6 +2,7 @@
export { default as IgcAvatarComponent } from './components/avatar/avatar.js';
export { default as IgcAccordionComponent } from './components/accordion/accordion.js';
export { default as IgcBadgeComponent } from './components/badge/badge.js';
+export { default as IgcBannerComponent } from './components/banner/banner.js';
export { default as IgcButtonComponent } from './components/button/button.js';
export { default as IgcButtonGroupComponent } from './components/button-group/button-group.js';
export { default as IgcCalendarComponent } from './components/calendar/calendar.js';
diff --git a/stories/banner.stories.ts b/stories/banner.stories.ts
new file mode 100644
index 000000000..54ba6ba35
--- /dev/null
+++ b/stories/banner.stories.ts
@@ -0,0 +1,98 @@
+import type { Meta, StoryObj } from '@storybook/web-components';
+import { html } from 'lit';
+
+import {
+ IgcBannerComponent,
+ IgcButtonComponent,
+ IgcIconComponent,
+ IgcNavbarComponent,
+ defineComponents,
+ registerIconFromText,
+} from '../src/index.js';
+
+defineComponents(
+ IgcBannerComponent,
+ IgcIconComponent,
+ IgcButtonComponent,
+ IgcNavbarComponent
+);
+
+// region default
+const metadata: Meta = {
+ title: 'Banner',
+ component: 'igc-banner',
+ parameters: {
+ docs: {
+ description: {
+ component:
+ 'The `igc-banner` component displays important and concise message(s) for a user to address, that is specific to a page or feature.',
+ },
+ },
+ actions: { handles: ['igcClosing', 'igcClosed'] },
+ },
+ argTypes: {
+ open: {
+ type: 'boolean',
+ description: 'Determines whether the banner is being shown/hidden.',
+ control: 'boolean',
+ table: { defaultValue: { summary: false } },
+ },
+ },
+ args: { open: false },
+};
+
+export default metadata;
+
+interface IgcBannerArgs {
+ /** Determines whether the banner is being shown/hidden. */
+ open: boolean;
+}
+type Story = StoryObj;
+
+// endregion
+
+const checkIcon =
+ '';
+
+registerIconFromText('success', checkIcon, 'material');
+
+const BasicTemplate = ({ open }: IgcBannerArgs) => {
+ return html`
+
+
+ Title
+
+
+ You are currently not logged in! Please, log into your account first.
+
+ Toggle Banner
+ `;
+};
+
+const SlottedContentTemplate = ({ open }: IgcBannerArgs) => {
+ return html`
+
+
+
+
+ Build f58a1815-c069-429d-ab20-860849e96a59 completed!
+
+
+ OK
+ View log
+
+
+ Toggle Banner
+ `;
+};
+
+export const Basic: Story = BasicTemplate.bind({});
+export const SlottedContent: Story = SlottedContentTemplate.bind({});