skip to Main Content

Essentially I am trying to write a tooltip component, and I would like for the tooltip dialogue to be absolutely positioned relative to the source of the tooltip. To accomplish this, I would need to wrap the dialog with the source and set the source to position:relative. The problem is that I would like for both the source and tooltip text to be slots/some form of HTML, so that I can pass arbitrary icons/formatted text.

I have already tried something like:

<slot name="source">
    <slot name="text"></slot>
</slot>

but from what I gather Vue won’t allow this, as I wasn’t able to find any examples of this in documentation and didn’t work when I tried it. I’ve also looked into dynamic/higher order components, but from what it looks like in Vue you have to define a set of possible components/import all of these components beforehand and slots are meant to be a stand in for this pattern.

2

Answers


  1. Does this solve the problem?

    <div class="source" style="position:relative">
      <slot name="source"></slot>
      <div class="text" style="position:abslute">
        <slot name="text"></slot>
      </div>
    </div>
    Login or Signup to reply.
  2. It’s not clear how you’d want to use your tooltip component, but you can do it this way:

    Vue SFC Playground

    <script setup>
    import { ref } from 'vue';
    import Tooltip from './Tooltip.vue';
    
    const msg = ref('Hello World!')
    
    </script>
    
    <template>
      <h1>{{ msg }}
        <tooltip>I am a <strong style="color: red">tooltip</strong></tooltip>
      </h1>
    </template>
    

    Tooltip.vue

    <script setup>
    import { onMounted, ref } from 'vue';
    const $dialog = ref();
    onMounted(() => {
      const {value: dialog} = $dialog;
      const {parentElement: parent} = dialog;
      parent.style.position = 'relative';  // @todo set if it's static, add the check
      parent.addEventListener('mouseenter', () => {
        dialog.style.left = 0;
        dialog.style.top = parent.offsetHeight + 5 + 'px'
        dialog.show();
      });
      parent.addEventListener('mouseleave', () => {
        dialog.close();
      });
    });
    
    </script>
    
    <template>
      <dialog ref="$dialog">
        <slot />
      </dialog>
    </template>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search