diff --git a/.storybook/main.js b/.storybook/main.js
index 5c21fbd88..bb892f02a 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -7,5 +7,5 @@ module.exports = {
     config.plugins.push(postCSS({ include: ['**/*.scss'], inject: false }));
 
     return config;
-  }
+  },
 };
diff --git a/.storybook/package.json b/.storybook/package.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/.storybook/package.json
@@ -0,0 +1 @@
+{}
diff --git a/package-lock.json b/package-lock.json
index cad591e95..a8e68fd26 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
       },
       "devDependencies": {
         "@igniteui/material-icons-extended": "^2.11.0",
+        "@lit-labs/testing": "^0.2.0",
         "@open-wc/eslint-config": "^9.2.2",
         "@open-wc/testing": "^3.1.7",
         "@storybook/storybook-deployer": "^2.8.16",
@@ -2016,11 +2017,92 @@
         "lit": "^2.0.2"
       }
     },
+    "node_modules/@lit-labs/ssr": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@lit-labs/ssr/-/ssr-3.0.0.tgz",
+      "integrity": "sha512-Gz3iiDFWBtoHNtDTcBTd4UuNkCa2FoxgpUnj1/t3iSaOwFur8fSJqkD8I0iXlMiVQA6SRC6e9aDPTmSL1HLR5g==",
+      "dev": true,
+      "dependencies": {
+        "@lit-labs/ssr-client": "^1.0.0",
+        "@lit-labs/ssr-dom-shim": "^1.0.0",
+        "@lit/reactive-element": "^1.6.0",
+        "@parse5/tools": "^0.1.0",
+        "@types/node": "^16.0.0",
+        "enhanced-resolve": "^5.10.0",
+        "lit": "^2.6.0",
+        "lit-element": "^3.1.0",
+        "lit-html": "^2.6.0",
+        "node-fetch": "^3.2.8",
+        "parse5": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=13.9.0"
+      }
+    },
+    "node_modules/@lit-labs/ssr-client": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lit-labs/ssr-client/-/ssr-client-1.0.1.tgz",
+      "integrity": "sha512-rr/UVhxbKWNUr+3qRyvZk+glC7v7ph8Gk/W0z96YG64COJKf9ilnWY6JGW77TRqhrRMmS2nsvAXOyQgcF+4jrA==",
+      "dev": true,
+      "dependencies": {
+        "@lit/reactive-element": "^1.0.0",
+        "lit": "^2.0.0",
+        "lit-html": "^2.0.0"
+      }
+    },
     "node_modules/@lit-labs/ssr-dom-shim": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.0.0.tgz",
       "integrity": "sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw=="
     },
+    "node_modules/@lit-labs/ssr/node_modules/@types/node": {
+      "version": "16.18.11",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz",
+      "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==",
+      "dev": true
+    },
+    "node_modules/@lit-labs/ssr/node_modules/node-fetch": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz",
+      "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==",
+      "dev": true,
+      "dependencies": {
+        "data-uri-to-buffer": "^4.0.0",
+        "fetch-blob": "^3.1.4",
+        "formdata-polyfill": "^4.0.10"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/node-fetch"
+      }
+    },
+    "node_modules/@lit-labs/ssr/node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/@lit-labs/testing": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@lit-labs/testing/-/testing-0.2.0.tgz",
+      "integrity": "sha512-cng801v8747kEn3Tlb9YaN+g/lvid3HLkr1NA9g+vMVaPd7kgqtqewdTZdZkRb52Hc10up2ey0vbVkAXliR2SA==",
+      "dev": true,
+      "dependencies": {
+        "@lit-labs/ssr": "^3.0.0",
+        "@web/test-runner-commands": "^0.6.1",
+        "@webcomponents/template-shadowroot": "^0.1.0",
+        "lit": "^2.6.0"
+      }
+    },
     "node_modules/@lit-labs/virtualizer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@lit-labs/virtualizer/-/virtualizer-1.0.1.tgz",
@@ -2344,6 +2426,27 @@
         "lit-html": "^2.0.0"
       }
     },
+    "node_modules/@parse5/tools": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@parse5/tools/-/tools-0.1.0.tgz",
+      "integrity": "sha512-VB9+4BsFoS+4HdB/Ph9jD4FHQt7GyiWESVNfBSh8Eu54LujWyy+NySGLjg8GZFWSZcESG72F67LjgmKZDZCvPg==",
+      "dev": true,
+      "dependencies": {
+        "parse5": "^7.0.0"
+      }
+    },
+    "node_modules/@parse5/tools/node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
     "node_modules/@rollup/plugin-babel": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -3563,6 +3666,12 @@
       "integrity": "sha512-qSok/oMynEgS99wFY5fKT6cR1y64i01RkHGYOspkh2JQsLSM8pjciER+gu3fqTx589y/7LoSuyB5G9Rh7dyXaQ==",
       "dev": true
     },
+    "node_modules/@webcomponents/template-shadowroot": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@webcomponents/template-shadowroot/-/template-shadowroot-0.1.0.tgz",
+      "integrity": "sha512-ry84Vft6xtRBbd4M/ptRodbOLodV5AD15TYhyRghCRgIcJJKmYmJ2v2BaaWxygENwh6Uq3zTfGPmlckKT/GXsQ==",
+      "dev": true
+    },
     "node_modules/@webcomponents/webcomponentsjs": {
       "version": "2.7.0",
       "resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.7.0.tgz",
@@ -5706,6 +5815,15 @@
         "node": ">=8.0.0"
       }
     },
+    "node_modules/data-uri-to-buffer": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
+      "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 12"
+      }
+    },
     "node_modules/date-fns": {
       "version": "2.29.3",
       "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
@@ -7464,6 +7582,29 @@
         "pend": "~1.2.0"
       }
     },
+    "node_modules/fetch-blob": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "dependencies": {
+        "node-domexception": "^1.0.0",
+        "web-streams-polyfill": "^3.0.3"
+      },
+      "engines": {
+        "node": "^12.20 || >= 14.13"
+      }
+    },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -7650,6 +7791,18 @@
         "is-callable": "^1.1.3"
       }
     },
+    "node_modules/formdata-polyfill": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+      "dev": true,
+      "dependencies": {
+        "fetch-blob": "^3.1.2"
+      },
+      "engines": {
+        "node": ">=12.20.0"
+      }
+    },
     "node_modules/fraction.js": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -11312,6 +11465,25 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/node-domexception": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "github",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "engines": {
+        "node": ">=10.5.0"
+      }
+    },
     "node_modules/node-fetch": {
       "version": "2.6.7",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -17083,6 +17255,15 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/web-streams-polyfill": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+      "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/webidl-conversions": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
diff --git a/package.json b/package.json
index 4d8af7921..a9608d40b 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
   "license": "SEE LICENSE IN LICENSE",
   "main": "dist/index.js",
   "module": "dist/index.js",
+  "type": "module",
   "repository": {
     "type": "git",
     "url": "https://github.com/IgniteUI/igniteui-webcomponents"
@@ -25,8 +26,8 @@
     "build:docs:json": "web-component-analyzer \"src/**/*.ts\" --format json --outDir docs/json",
     "build:docs:schema": "web-component-analyzer src --format json --outFile custom-elements.json",
     "build:docs:vscode-schema": "web-component-analyzer src --format vscode --outFile vscode-html-custom-data.json",
-    "build:meta": "node scripts/build-stories.js",
-    "watch-meta": "node scripts/stories-watcher.js ",
+    "build:meta": "node scripts/build-stories.mjs",
+    "watch-meta": "node scripts/stories-watcher.mjs ",
     "watch-scss": "node scripts/styles-watcher.mjs",
     "watch-ts": "tsc --watch --preserveWatchOutput",
     "check": "madge --circular --warning --no-spinner dist/src/index.js",
@@ -45,10 +46,10 @@
     "test:watch": "npm run build && concurrently -k -r \"npm:watch-scss\" \"npm:watch-ts\" \"wtr --watch\"",
     "storybook": "npm run build && concurrently -k -r \"npm:watch-scss\" \"npm:watch-ts\" \"npm:watch-meta\" \"wds -c .storybook/server.mjs\"",
     "storybook:build": "npm run build && build-storybook -o ./storybook-static",
-    "build:typedoc:watch": "node scripts/build-typedoc.js watch",
-    "build:typedoc:serve": "node scripts/build-typedoc.js serve  && concurrently -k -r \"npm:build:typedoc:watch\"",
-    "build:typedoc:ja": "set NODE_ENV=production && node scripts/build-typedoc.js buildJA",
-    "build:typedoc:en": "set NODE_ENV=production && node scripts/build-typedoc.js buildEN",
+    "build:typedoc:watch": "node scripts/build-typedoc.mjs watch",
+    "build:typedoc:serve": "node scripts/build-typedoc.mjs serve  && concurrently -k -r \"npm:build:typedoc:watch\"",
+    "build:typedoc:ja": "set NODE_ENV=production && node scripts/build-typedoc.mjs buildJA",
+    "build:typedoc:en": "set NODE_ENV=production && node scripts/build-typedoc.mjs buildEN",
     "deploy-storybook": "storybook-to-ghpages --ci --existing-output-dir=./storybook-static",
     "prepare": "husky install"
   },
@@ -59,6 +60,7 @@
   },
   "devDependencies": {
     "@igniteui/material-icons-extended": "^2.11.0",
+    "@lit-labs/testing": "^0.2.0",
     "@open-wc/eslint-config": "^9.2.2",
     "@open-wc/testing": "^3.1.7",
     "@storybook/storybook-deployer": "^2.8.16",
diff --git a/scripts/build-stories.js b/scripts/build-stories.mjs
similarity index 94%
rename from scripts/build-stories.js
rename to scripts/build-stories.mjs
index dfaad2dc5..7f7244844 100644
--- a/scripts/build-stories.js
+++ b/scripts/build-stories.mjs
@@ -1,8 +1,12 @@
-const fs = require('fs');
-const path = require('path');
-const util = require('util');
-const prettier = require('prettier');
-const report = require('./report');
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import util from 'node:util';
+import prettier from 'prettier';
+
+import report from './report.mjs';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
 
 const readFile = util.promisify(fs.readFile);
 const writeFile = util.promisify(fs.writeFile);
diff --git a/scripts/build-styles.mjs b/scripts/build-styles.mjs
index 3386dac58..7b8b30251 100644
--- a/scripts/build-styles.mjs
+++ b/scripts/build-styles.mjs
@@ -1,5 +1,5 @@
 import { globby } from 'globby';
-import report from './report.js';
+import report from './report.mjs';
 import { sassRender, template } from './sass.mjs';
 
 (async () => {
@@ -19,5 +19,8 @@ import { sassRender, template } from './sass.mjs';
       process.exit(-1);
     });
   }
-  report.success(`Styles generated in ${Math.round((Date.now() - startTime) / 1000)}s`);
+
+  report.success(
+    `Styles generated in ${Math.round((Date.now() - startTime) / 1000)}s`
+  );
 })();
diff --git a/scripts/build-typedoc.js b/scripts/build-typedoc.mjs
similarity index 76%
rename from scripts/build-typedoc.js
rename to scripts/build-typedoc.mjs
index b706a897e..f73c3cfd0 100644
--- a/scripts/build-typedoc.js
+++ b/scripts/build-typedoc.mjs
@@ -1,30 +1,37 @@
-const path = require('path');
-const watch = require('node-watch');
-const { promisify } = require('util');
-const browserSync = require('browser-sync').create();
-const exec = promisify(require('child_process').exec);
+import path from 'node:path';
+import watch from 'node-watch';
+import { promisify } from 'node:util';
+import { create } from 'browser-sync';
+import { exec as _exec } from 'node:child_process';
+
+const browserSync = create();
+const exec = promisify(_exec);
 
 const ROOT = path.join.bind(null, path.resolve('./'));
 
 const TYPEDOC_THEME = {
   SRC: ROOT('node_modules', 'igniteui-typedoc-theme'),
-  OUTPUT: ROOT('dist', 'docs', 'typescript')
+  OUTPUT: ROOT('dist', 'docs', 'typescript'),
 };
 const TYPEDOC = {
   EXPORT_JSON_PATH: ROOT('dist', 'docs', 'typescript-exported'),
   PROJECT_PATH: ROOT('src', 'index.ts'),
-  TEMPLATE_STRINGS_PATH: ROOT('extras', 'template', 'strings', 'shell-strings.json')
+  TEMPLATE_STRINGS_PATH: ROOT(
+    'extras',
+    'template',
+    'strings',
+    'shell-strings.json'
+  ),
 };
 
-
 const browserReload = async () => browserSync.reload();
 
 const serve = async () => {
   const config = {
     server: {
-      baseDir: TYPEDOC_THEME.OUTPUT
+      baseDir: TYPEDOC_THEME.OUTPUT,
     },
-    port: 3000
+    port: 3000,
   };
   browserSync.init(config);
 };
@@ -35,7 +42,7 @@ const watchFunc = async () => {
     recursive: true,
     filter: (path) => {
       return /.(?:ts|js|scss|sass|hbs|png|jpg|gif)$/.test(path);
-    }
+    },
   };
 
   watch([TYPEDOC_THEME.SRC], options, async (event, path) => {
@@ -45,7 +52,10 @@ const watchFunc = async () => {
 };
 
 const buildTheme = async () => {
-  await exec(`typedoc ${TYPEDOC.PROJECT_PATH} --tsconfig ${ROOT('tsconfig.json')}`, { shell: true });
+  await exec(
+    `typedoc ${TYPEDOC.PROJECT_PATH} --tsconfig ${ROOT('tsconfig.json')}`,
+    { shell: true }
+  );
 };
 
 const exportJSON = async () => {
@@ -56,7 +66,7 @@ const exportJSON = async () => {
     '--tags',
     '--params',
     '--tsconfig',
-    ROOT('tsconfig.json')
+    ROOT('tsconfig.json'),
   ].join(' ');
 
   await exec(`typedoc ${args}`, { shell: true });
@@ -69,7 +79,7 @@ const importJSON = async () => {
     TYPEDOC.EXPORT_JSON_PATH,
     '--warns',
     '--tsconfig',
-    ROOT('tsconfig.json')
+    ROOT('tsconfig.json'),
   ].join(' ');
 
   await exec(`typedoc ${args}`, { shell: true });
@@ -86,25 +96,24 @@ const buildJA = async () => {
     '--localize',
     'jp',
     '--tsconfig',
-    ROOT('tsconfig.json')
+    ROOT('tsconfig.json'),
   ].join(' ');
 
   await exec(`typedoc ${args}`, { shell: true });
-}
+};
 
 const buildEN = async () => {
   const args = [
     TYPEDOC.PROJECT_PATH,
     '--localize',
     'en',
-    "--tsconfig",
-    ROOT('tsconfig.json')
+    '--tsconfig',
+    ROOT('tsconfig.json'),
   ].join(' ');
 
   await exec(`typedoc ${args}`, { shell: true });
 };
 
-
 (async () => {
   if (process.argv.length < 3) {
     throw new Error('No action argument provided');
diff --git a/scripts/report.js b/scripts/report.js
deleted file mode 100644
index 9f39e9928..000000000
--- a/scripts/report.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
-  success: (s) => console.log("\x1b[32m%s\x1b[0m", s),
-  warn: (s) => console.warn("\x1b[33m%s\x1b[0m", s),
-  error: (s) => console.error("\x1b[31m%s\x1b[0m", s),
-};
diff --git a/scripts/report.mjs b/scripts/report.mjs
new file mode 100644
index 000000000..282b953a5
--- /dev/null
+++ b/scripts/report.mjs
@@ -0,0 +1,6 @@
+export default {
+  success: (s) => console.log('\x1b[32m%s\x1b[0m', s),
+  warn: (s) => console.warn('\x1b[33m%s\x1b[0m', s),
+  error: (s) => console.error('\x1b[31m%s\x1b[0m', s),
+  info: (s) => console.log('\x1b[36m%s\x1b[0m', s),
+};
diff --git a/scripts/stories-watcher.js b/scripts/stories-watcher.js
deleted file mode 100644
index 31a12db39..000000000
--- a/scripts/stories-watcher.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const watch = require('node-watch');
-const {promisify} = require('util');
-const exec = promisify(require('child_process').exec);
-
-const watchOptions = {
-  recursive: true,
-  filter: (path) => {
-    return /^((?!\.spec|.css\.).)*\.ts$/.test(path);
-  },
-};
-
-watch(['src'], watchOptions, function(_event, fileName) {
-  addToQueue(fileName);
-});
-
-let updating = false;
-
-async function addToQueue(fileName) {
-  if (updating) {
-    return;
-  }
-  console.log(`Component change detected: ${fileName}`);
-  updating = true;
-  console.log('Building documentation metadata and updating stories...');
-
-  const buildDocsPromise = exec('npm run build:docs:json && npm run build:meta');
-
-  try {
-    await buildDocsPromise;
-    updating = false;
-    console.log('Metadata build completed. Stories updated.');
-  } catch (e) {
-    console.error("ERROR:", e);
-  }
-}
-
-console.log('Metadata watcher started...');
diff --git a/scripts/stories-watcher.mjs b/scripts/stories-watcher.mjs
new file mode 100644
index 000000000..011f1f1d7
--- /dev/null
+++ b/scripts/stories-watcher.mjs
@@ -0,0 +1,43 @@
+import { promisify } from 'node:util';
+import { exec as exec_ } from 'node:child_process';
+import watch from 'node-watch';
+
+import report from './report.mjs';
+
+const exec = promisify(exec_);
+
+const watchOptions = {
+  recursive: true,
+  filter: (path) => {
+    return /^((?!\.spec|.css\.).)*\.ts$/.test(path);
+  },
+};
+
+watch(['src'], watchOptions, function (_event, fileName) {
+  addToQueue(fileName);
+});
+
+let updating = false;
+
+async function addToQueue(fileName) {
+  if (updating) {
+    return;
+  }
+  report.info(`Component change detected: ${fileName}`);
+  updating = true;
+  report.info('Building documentation metadata and updating stories...');
+
+  const buildDocsPromise = exec(
+    'npm run build:docs:json && npm run build:meta'
+  );
+
+  try {
+    await buildDocsPromise;
+    updating = false;
+    report.success('Metadata build completed. Stories updated.');
+  } catch (e) {
+    report.error('ERROR:', e);
+  }
+}
+
+report.info('Metadata watcher started...');
diff --git a/scripts/styles-watcher.mjs b/scripts/styles-watcher.mjs
index be15795c8..8693649dd 100644
--- a/scripts/styles-watcher.mjs
+++ b/scripts/styles-watcher.mjs
@@ -1,5 +1,5 @@
 import watch from 'node-watch';
-import report from './report.js';
+import report from './report.mjs';
 import { sassRender, template } from './sass.mjs';
 
 const watchOptions = {
@@ -9,7 +9,7 @@ const watchOptions = {
   },
 };
 
-watch(['src'], watchOptions, function(_event, fileName) {
+watch(['src'], watchOptions, function (_event, fileName) {
   addToQueue(fileName);
 });
 
@@ -22,7 +22,7 @@ async function addToQueue(fileName) {
   }
   report.warn(`Change detected: ${fileName}`);
   updating = true;
-  console.log('Rebuilding styles...');
+  report.info('Rebuilding styles...');
 
   await sassRender(fileName, template, output).catch((err) => {
     report.error(err);
@@ -31,4 +31,4 @@ async function addToQueue(fileName) {
   updating = false;
 }
 
-console.log('Styles watcher started...');
+report.info('Styles watcher started...');
diff --git a/src/components/avatar/avatar.ssr.spec.ts b/src/components/avatar/avatar.ssr.spec.ts
new file mode 100644
index 000000000..5877ca1b4
--- /dev/null
+++ b/src/components/avatar/avatar.ssr.spec.ts
@@ -0,0 +1,43 @@
+import {
+  csrFixture,
+  ssrNonHydratedFixture,
+  ssrHydratedFixture,
+  cleanupFixtures,
+} from '@lit-labs/testing/fixtures.js';
+import { html } from 'lit';
+import { expect } from '@open-wc/testing';
+import { defineComponents } from '../common/definitions/defineComponents.js';
+import IgcAvatarComponent from './avatar.js';
+
+defineComponents(IgcAvatarComponent);
+
+after(() => cleanupFixtures());
+
+for (const fixture of [csrFixture, ssrNonHydratedFixture, ssrHydratedFixture]) {
+  describe(`Avatar rendered with ${fixture.name}`, () => {
+    it('is defined', () => {
+      const el = document.createElement(IgcAvatarComponent.tagName);
+      expect(el).instanceOf(IgcAvatarComponent);
+    });
+
+    it('renders with default values', async () => {
+      const el = await fixture(html`