MCPcopy Index your code
hub / github.com/EranGrin/vue-web-component-wrapper

github.com/EranGrin/vue-web-component-wrapper @1.7.7

Chat with this repo
repository ↗ · DeepWiki ↗ · release 1.7.7 ↗ · + Follow
50 symbols 116 edges 34 files 3 documented · 6%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README
<h1 align="center">vue-web-component-wrapper</h1>






<em>Transforming full-fledged Vue3 applications into reusable web components</em>






<img src="https://img.shields.io/badge/license-MIT-green" alt="License MIT">
<img src="https://img.shields.io/badge/version-1.7.7-blue" alt="version 1.7.7">
<img src="https://img.shields.io/badge/maintained-yes-brightgreen" alt="maintained yes">

Introduction

vue-web-component-wrapper is a powerful Vue 3 plugin designed to transform full-fledged Vue applications into reusable web components (custom elements). These web components can be integrated into any website, enhancing flexibility and reusability.

Why Use vue-web-component-wrapper?

As of now, Vue 3 does not support the creation of full applications as web components out of the box. This plugin aims to solve this problem by providing a simple and easy-to-use solution for creating web components from Vue applications. It also provides support for Vue ecosystem plugins such as Vuex, Pinia, Vue Router, Vue I18n, and VeeValidate.

Demo

Check out these demo projects to see vue-web-component-wrapper in action:

Documentation

See the Documentation for more details.

Key Features

  • Vue Plugins Compatibility: Seamlessly integrates with Vue ecosystem plugins like Vuex, Vue Router, and Vue I18n.
  • CSS Framework Support: Works with popular CSS frameworks such as Tailwind CSS, Bootstrap, Vuetify, Element Plus, and more.
  • CSS Preprocessor Support: Allows the use of CSS preprocessors like SCSS and LESS.
  • Scoped CSS: Supports scoped CSS in your components.
  • Shadow DOM Support: Encapsulates styles and scripts to prevent clashes with the rest of your application.
  • Vue DevTools Support: Compatible with the Vue DevTools browser extension.
  • Slot and Named Slot Support: Define and use slots and named slots within web components.
  • v-model Support: Improved support for two-way data binding using the v-model architecture.
  • Event Emitting Support: Emit and handle custom events from web components.
  • Provide/Inject Support: Pass data from parent to child components using provide and inject.
  • Disable Removal of Styles on Unmount: Control the removal of styles upon component unmount to solve issues with CSS transitions.
  • Disable Shadow DOM: Option to disable Shadow DOM for web components.
  • Replace :root with :host: Optionally replace :root selectors with :host in your CSS to ensure styles are correctly scoped within the Shadow DOM.
  • Async Initialization: Option to delay the initialization until its Promise resolves.
  • Loader Support: Support for loader spinner elements until the application is fully initialized.
  • Hide slot content until the component is fully mounted: Option to hide the content of named slots until the web-component is fully mounted.

CSS Frameworks Examples

For more details, see the Documentation.

Installation

npm install vue-web-component-wrapper
# or
yarn add vue-web-component-wrapper
# or
pnpm add vue-web-component-wrapper

Usage

To create a web component using vue-web-component-wrapper, follow the steps below:

1. Import the Necessary Modules

In your entry file, import the required modules:

import App from './App.vue';
import tailwindStyles from './assets/tailwind.css?raw';
import { createWebHashHistory, createRouter } from 'vue-router';
import { createI18n } from 'vue-i18n';
import { createStore } from 'vuex';
import { createPinia } from 'pinia';
import { defaultRoutes } from './main.routes.js';
import { store } from './store/index.js';
import {
  defineCustomElement as VueDefineCustomElement,
  h,
  createApp,
  getCurrentInstance,
} from 'vue';
import { createWebComponent } from 'vue-web-component-wrapper';

2. Set Up the Instances and Plugins

Configure your Vuex/Pinia store, Vue Router, and other Vue plugins:

export const pluginsWrapper = {
  install(GivenVue) {
    const Vue = GivenVue;

    // Vuex
    const createdStore = createStore(store);
    Vue.use(createdStore);

    // Or Pinia
    const pinia = createPinia();
    Vue.use(pinia);

    // Vue Router
    const router = createRouter({
      history: createWebHashHistory(),
      routes: defaultRoutes,
    });
    Vue.use(router);

    // Vue I18n
    const i18n = createI18n({
      locale: 'en',
      fallbackLocale: 'en',
    });
    Vue.use(i18n);
  },
};

3. Create Your Web Component

Use createWebComponent to create your web component. Specify your root Vue component, the element name, any plugins, and CSS framework styles:

createWebComponent({
  rootComponent: App,
  elementName: 'my-web-component',
  plugins: pluginsWrapper,
  cssFrameworkStyles: tailwindStyles,
  VueDefineCustomElement,
  h,
  createApp,
  getCurrentInstance,
  disableStyleRemoval: false, // default is false
  disableShadowDOM: false,    // default is false
  replaceRootWithHostInCssFramework: false, // default is false
  loaderAttribute: 'data-web-component-loader', // default is 'data-web-component-loader'
  hideSlotContentUntilMounted: true, // default is false
});

Options Explained

  • rootComponent: The root component of your Vue application.
  • elementName: The tag name for your custom web component (must contain a hyphen and be lowercase).
  • plugins: Vue plugins to use in your application.
  • cssFrameworkStyles: Global CSS or SCSS styles your application needs.
  • VueDefineCustomElement: The defineCustomElement function from Vue.
  • h: The h function from Vue.
  • createApp: The createApp function from Vue.
  • getCurrentInstance: The getCurrentInstance function from Vue.
  • disableStyleRemoval: Disable removal of styles on unmount (useful for CSS transitions).
  • disableShadowDOM: Disable Shadow DOM for web components.
  • replaceRootWithHostInCssFramework: Replace :root selectors with :host in your CSS styles.
  • asyncInitialization: Accepts a function that returns a Promise.
  • loaderAttribute: Defines the attribute used to mark loader spinner (default is data-web-component-loader).
  • hideSlotContentUntilMounted: Hide the content of named slots until the component is fully mounted.
  • nonce: Content Security Policy (CSP) nonce for your web component.

asyncInitialization

The asyncInitialization option accepts a function that returns a Promise. The custom element waits for this Promise to resolve before completing its initialization. This is useful for performing asynchronous tasks (e.g., API calls, dynamic imports) before the app mounts.

Example Usage

const asyncPromise = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, 1000)
  })
}

createWebComponent({
  rootComponent: App,
  elementName: 'my-web-component',
  plugins: pluginsWrapper,
  cssFrameworkStyles: tailwindStyles,
  VueDefineCustomElement,
  h,
  createApp,
  getCurrentInstance,
  asyncInitialization: asyncPromise, // default is Promise.resolve()
  loaderAttribute: 'data-web-component-loader',
  hideSlotContentUntilMounted: true, // default is false
});

loaderAttribute

The loaderAttribute option defines the attribute used to mark loader spinner elements in your custom element's DOM. Elements with this attribute will be removed automatically once the component is fully mounted.

    <my-web-component
      class="my-web-component"
    >












    </my-web-component>

  <style>
    .spinner {
    border: 4px solid rgba(0, 0, 0, 0.1);
    border-left-color: #4a90e2; /* Customize spinner color if needed */
    border-radius: 50%;
    width: 30px;
    height: 30px;
    animation: spin 1s linear infinite;
    margin: auto;
  }

  @keyframes spin {
    to {
      transform: rotate(360deg);
    }
  }
  </style>

hideSlotContentUntilMounted

The hideSlotContentUntilMounted option hides the content of named slots until the component is fully mounted. - By using the hidden attribute on the slot element, the content will be hidden until the component is fully mounted, and the web component wrapper will remove the hidden attribute once the component is fully mounted. - This could be break the layout of your application, if you use the hidden attribute internally in your application. - If you want to use the hidden attribute internally in your application, you can set the hideSlotContentUntilMounted option to false.

<my-web-component>



I am a custom named slot 


</my-web-component>

replaceRootWithHostInCssFramework

The replaceRootWithHostInCssFramework option replaces all occurrences of :root with :host in your cssFrameworkStyles. This is useful when working with CSS variables defined on :root, ensuring they are properly scoped within the Shadow DOM.

Example Usage

createWebComponent({
  rootComponent: App,
  elementName: 'my-web-component',
  plugins: pluginsWrapper,
  cssFrameworkStyles: tailwindStyles,
  VueDefineCustomElement,
  h,
  createApp,
  getCurrentInstance,
  replaceRootWithHost: true,
});

cssFrameworkStyles

The cssFrameworkStyles option imports the CSS of your CSS framework or any other global CSS styles your application needs. By setting replaceRootWithHostInCssFramework to true, any :root selectors in your styles will be replaced with :host, ensuring correct scoping within the web component.

nonce

The nonce option is used to set a Content Security Policy (CSP) nonce for your web component. This is useful when your application uses inline scripts or styles, as it allows you to specify a unique nonce value that can be used to whitelist the inline content.

4. Build Your Application

Tested bundlers to build the web-component application.

Bundler Configurations

Vite Configuration

Vite.js Configuration

Here's a sample Vite configuration. Vite.js handles asset files like .css and .scss, and media files, importing them as usual. Vue files are parsed using the official @vitejs/plugin-vue.

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  build: {
    sourcemap: 'inline',
  },
  plugins: [
    vue({
      customElement: true,
    }),
  ],
});

main.js/ts

In your main file, import the CSS framework with ?inline:

// Fonts are not loaded with ?inline; import font CSS in App.vue
import style from './style.css?inline';

App.vue

Workaround for fonts:

<style>
@import url('https://fonts.googleapis.com/css2?family=YourFont');

header {
  @apply font-sans;
}

main {
  @apply font-sans;
}
</style>

Webpack Configuration

Webpack Configuration

Here's a sample webpack configuration to handle .vue, .css, and .scss files:

```javascript const path = require('path'); const { VueLoaderPlugin } = require('vue-loader'); const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = { mode: 'production', entry: './src/main.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-web-component.js', }, module: { rules: [ { test: /.(vue|ce.vue)$/, loader: 'vue-loader', options: { customElement: true, }, }, { test: /.(css|scss)$/, oneOf: [ { resourceQuery: /raw/, use: [ 'to-string-loader', 'css-loader', 'postcss-loader', { loader: 'sass-loader', options: { sassOptions: { indentedSyntax: false, }, }, }, ], }, { use: [ 'style-loader', 'css-loader', 'postcss-loader', { loader: 'sass-loader', options: { sassOptions: { indentedSyntax: false, }, }, }, ], }, ], }, { test: /.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'file-loader', options: { name: 'assets/[name].[hash:7].[ext]', },

Extension points exported contracts — how you extend this code

Plugin (Interface)
(no doc)
package/types.d.ts
DefineCustomElementConfig (Interface)
(no doc)
package/src/api-custom-element.ts
GlobalComponents (Interface)
(no doc)
demo-app-vite/components.d.ts
ImportMetaEnv (Interface)
(no doc)
demo-app-vite/env.d.ts
ComponentCustomProperties (Interface)
(no doc)
demo-app-vite/auto-imports.d.ts
CreateWebComponentOptions (Interface)
(no doc)
package/types.d.ts
ComponentInternalInstanceCe (Interface)
(no doc)
package/src/api-custom-element.ts
ImportMeta (Interface)
(no doc)
demo-app-vite/env.d.ts

Core symbols most depended-on inside this repo

createWebComponent
called by 4
package/index.js
resolve
called by 4
package/src/api-custom-element.ts
_update
called by 4
package/src/api-custom-element.ts
_setProp
called by 3
package/src/api-custom-element.ts
defineCustomElement
called by 2
package/src/api-custom-element.ts
_resolveProps
called by 2
package/src/api-custom-element.ts
_setAttr
called by 2
package/src/api-custom-element.ts
_createVNode
called by 2
package/src/api-custom-element.ts

Shape

Method 19
Function 16
Interface 9
Class 6

Languages

TypeScript100%

Modules by API surface

package/src/api-custom-element.ts28 symbols
package/src/web-component-util.js8 symbols
package/types.d.ts3 symbols
demo-app-vite/src/pinia/counter.store.ts2 symbols
demo-app-vite/env.d.ts2 symbols
package/index.js1 symbols
demo-app-webpack/src/main.js1 symbols
demo-app-webpack/plugins.js1 symbols
demo-app-vite/src/plugins/index.ts1 symbols
demo-app-vite/src/main.ts1 symbols
demo-app-vite/components.d.ts1 symbols
demo-app-vite/auto-imports.d.ts1 symbols

For agents

$ claude mcp add vue-web-component-wrapper \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page