Skip to content

Conversation

@alexisreina
Copy link

@alexisreina alexisreina commented Nov 5, 2025

Create a new styleContainer option in primevue config to be able to pass via configuration where the style tags need to be injected, allowing to pass the shadowRoot in the defineCustomElement setup function and keeping the existing functionality without breaking changes.

Example use:

import { defineCustomElement, getCurrentInstance, h, useShadowRoot } from 'vue'
import App from './App.vue';
import PrimeVue from 'primevue/config';
import Aura from '@primeuix/themes/aura';


// Define the custom element with all the
const MyWebComponent = defineCustomElement({
  setup() {
    const instance = getCurrentInstance()
    const app = instance?.appContext.app
    app?.use(PrimeVue, {
      styleContainer: useShadowRoot() ?? undefined,
      theme: {
        preset: Aura,
      },
    })

    return () => h(App)
  },
})

// Auto-register the custom element
customElements.define('my-web-component', MyWebComponent);

This is a much simpler proposal than #7351 that will also help with #4001 that will add support for custom elements to the library without breaking changes.

Components that use the Portal like the dialog will be rendered by default in the body and the styles will be added to the shadowRoot, consumers will have to handle this situation in their custom elements, by either coping the styles to the document head or by passing a template ref as anchorEl to render this components inside the shadowRoot.

Example

<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
import { Button, Dialog } from 'primevue'

const visible = ref(false)
const portal = useTemplateRef('portal')

const openDialog = () => {
  visible.value = true
}

const closeDialog = () => {
  visible.value = false
}
</script>
<template>
  <div class="fixed right-8 bottom-8">
    <Button label="Open Dialog" @click="openDialog" raised size="large" />
    <Dialog
      :visible="visible"
      :appendTo="portal"
      header="I'm a dialog"
      @update:visible="closeDialog"
      class="w-full max-w-md"
    >
      <p class="f-body-md text-surface-700">This is the dialog body</p>
      <template #footer>
        <Button label="Close" @click="closeDialog" outlined />
      </template>
    </Dialog>
  </div>
  <div ref="portal"></div>
</template>

This fix was tested locally, and the styles are correctly copied to the shadowRoot, when building a "regular" vue app or a custom element without a shadow dom, the styles are injected to the document head and everything works as usual

Screenshot 2025-11-05 at 17 51 11 Screenshot 2025-11-05 at 17 52 32

@alexisreina alexisreina changed the title feat: custom elements support fix: custom elements support Nov 5, 2025
@alexisreina alexisreina changed the title fix: custom elements support feat: custom elements support Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant