Skip to content

🧬 Add attributes and event-listeners to <slot> content πŸ’‰

License

Notifications You must be signed in to change notification settings

privatenumber/vue-vnode-syringe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

67 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ’‰ vNode Syringe Latest version Monthly downloads Install size Bundle size

Add attributes and event-listeners to <slot> content.

Supports key, class/style, attrs, props & listeners!

<template>
    <div>
        <vnode-syringe
            class="new-class"
            @click="handleClick"
        >
            <slot />   β¬… The class and event-listener gets added to every element passed in
        </vnode-syringe>
    </div>
</template>

πŸ™‹β€β™‚οΈ Why?

  • πŸ”₯ Set or overwrite attributes & event-listeners on content received from the <slot>!
  • 🧠 Smart merging strategies Pick between merging, overwriting, or falling-back!
  • πŸ₯ Tiny 1.05 KB minzipped!

πŸš€ Install

npm i vue-vnode-syringe

πŸ’  Merging strategies

Fallback

This is the default behavior. The class new-class and event-listener newOnClick only gets added if there isn't one added yet.

<vnode-syringe
    class="new-class"
    @click="newOnClick"
>
    <slot />
</vnode-syringe>

For example, given the following <slot> content, only the event-listener newOnClick will be added:

<div
	class="some-class"
	<!-- @click="newOnClick" gets added -->
>
    some content
</div>

Overwrite !

Add ! at the end of the attribute or event-listener to overwrite what exists.

<vnode-syringe
    class!="new-class"
    @click!="newOnClick"
>
    <slot />
</vnode-syringe>

For example, given the following <slot> content, both the class and event-listener will overwrite the existing class and event-listener.

<div
    class="some-class" <!-- becomes "new-class" -->
    @click="existing" <!-- becomes "newOnClick" -->
>
    some content
</div>

Merge &

Add & at the end of the attribute or event-listener to merge with what exists.

<vnode-syringe
    class&="new-class"
    @click&="newOnClick"
>
    <slot />
</vnode-syringe>

For example, given the following <slot> content, both the class and event-listener will merge with the existing class and event-listener. When merging event-listeners, both event-listeners will be called.

<div
    class="some-class" <!-- becomes "some-class new-class" -->
    @click="existing" <!-- becomes "existing(); newOnClick()" -->
>
    some content
</div>

πŸ‘¨πŸ»β€πŸ« Examples

Demo 1: Passing down attributes

In this demo, the class="button-group__button" attribute is passed down to all of its <slot> content.

ButtonGroup.vue

<template>
    <div class="button-group">
        <vnode-syringe
            class="button-group__button"
        >
            <slot />
        </vnode-syringe>
    </div>
</template>

<style scoped>
.button-group { ... }
.button-group__button { ... }
</style>

Usage.vue

<button-group>
    <button>Button 1</button> <!-- Will render with the `button-group__button` class -->
    <button>Button 2</button> <!-- Will render with the `button-group__button` class -->
    <button>Button 3</button> <!-- Will render with the `button-group__button` class -->
</button-group>
Demo 2: Merging and Overwriting classes

By default, vNode Syringe only adds the attribute/event-listener if it doesn't already exist. To merge with or overwrite the existing one, use the & (merge) or ! (overwrite) suffix.

ButtonGroup.vue

<template>
    <div class="button-group">
        <vnode-syringe

            <!-- Merge with existing class -->
            class&="button-group__button"

            <!-- Force all buttons to have type="button" -->
            type!="button"

            <!-- Only gets added if child doesn't specify `disabled` -->
            :disabled="disabled"
        >
            <slot />
        </vnode-syringe>
    </div>
</template>

<script>
export default {
    props: {
        disabled: Boolean
    }
};
</script>

<style scoped>
.button-group { ... }
.button-group__button { ... }
</style>

Usage.vue

<button-group disabled>
    <button

         <!-- Gets overwritten to button button-group__button -->
        class="button"

        <!-- Gets overwritten to type="button" -->
        type="submit"

        <!-- Will be inherit parent's disabled state -->
    >
        Button 1
    </button>

    <button
         <!-- Gets overwritten to button button-group__button -->
        class="button"

        <!-- Won't inherit parent's disabled state -->
        :disabled="false"
    >
        Button 2
    </button>
</button-group>

πŸ’β€β™€οΈ FAQ

How can I add attributes/event-listeners to a specific element in the <slot>?

You can use Subslot to pick out specific elements in the slot.

For example, if you only want to accept <button>s in your slot:

<template>
    <div class="button-group">
        <vnode-syringe
            class&="button-group-item"
            @click="onClick"
        >
            <subslot element="button" />
        </vnode-syringe>
    </div>
</template>

<script>
import Subslot from 'vue-subslot';
import vnodeSyringe from 'vue-vnode-syringe';

export default {
    components: {
        Subslot,
        vnodeSyringe
    },

    ...,

    methods: {
        onClick() {
            ...
        }
    }
};
</script>

πŸ‘¨β€πŸ‘©β€πŸ‘§ Related

  • vue-proxi - πŸ’  Tiny proxy component
  • vue-subslot - πŸ’ Pick 'n choose what you want from a slot passed into your Vue component
  • vue-pseudo-window - πŸ–Ό Declaratively interface window/document in your Vue template
  • vue-v - render vNodes via component template
  • vue-frag - 🀲 Directive to return multiple root elements