LinusBorg / portal-vue

A feature-rich Portal Plugin for Vue 3, for rendering DOM outside of a component, anywhere in your app or the entire document. (Vue 2 version: v2.portal-vue.linusb.org)
http://portal-vue.linusb.org
MIT License
3.89k stars 186 forks source link

Class passed to component is lost in the portal #101

Open lazlo-bonin opened 6 years ago

lazlo-bonin commented 6 years ago

I use portal-vue in order to move all my modals at the top level for z-ordering. My dialog component setup is like so:

<template>
    <portal to="dialogs">
        <div class="dialog-mask">
            <div class="dialog-container">
                ...

When I try to use the component, I often do something like:

<dialog class="myDialogClass">...</dialog>

However, when the <div> is rendered in the portal-target, it only has the dialog-mask class, not dialog-mask myDialogClass.

I'm struggling to get the class property to bind. I could use a custom dialogClass prop and do it manually, but I'd rather use vue's built-in clear syntax.

Am I missing something?

LinusBorg commented 6 years ago

You are missing that the class that you define on the component will be added to its root element - which is the portal, not the div inside it.

However, you can set inheritAttrs: false in the component containing the portal and then use $attrs to pass any attributes defined in the component to that div instead:

<div class="dialog-mask" v-bind="$attrs">

Please see the Vue documentation for those two properties of you want to learn more.

lazlo-bonin commented 6 years ago

The Vue documentation states:

Note: this option does not affect class and style bindings.

Any other solution?

Edit: Seeing this issue, I ended up using a custom prop after all:

https://github.com/vuejs/vue/issues/6144

LinusBorg commented 6 years ago

Oh, right, forgot about that limitation.

I will add this to the caveats section in the docs later.

tmorehouse commented 5 years ago

If the dialog has a single root element, wouldn't the slim option make the inner content the root element (this.$el) and the class would be placed in it? or is that relationship lost during transport?

tmorehouse commented 5 years ago

Just realized that slim is only applicable to disabled mode.

I also tried setting portal's tag to transition (which has the nice effect of rendering <!----> instead of a visually hidden div), but still the same effect of not transferring the class to the root element.

LinusBorg commented 5 years ago

or is that relationship lost during transport

This. There's really no way to make this work.

GerardRodes commented 4 years ago

It feels hacky but i solved this using $vnode.data.staticClass

<template>
  <portal to="root">
    <div :class="$vnode.data.staticClass" />
  </portal>
</template>

This way class (and potentially any data inside vnode) can be pass down through the portal