{"id":16347751,"url":"https://github.com/privatenumber/vue-vnode-syringe","last_synced_at":"2025-03-21T00:30:24.258Z","repository":{"id":53127088,"uuid":"247495530","full_name":"privatenumber/vue-vnode-syringe","owner":"privatenumber","description":"🧬 Add attributes and event-listeners to \u003cslot\u003e content 💉","archived":false,"fork":false,"pushed_at":"2021-04-05T17:03:02.000Z","size":881,"stargazers_count":22,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-17T18:53:54.796Z","etag":null,"topics":["attributes","event-listeners","merge","mutate","overwrite","props","slot","vnode","vnode-syringe","vue"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/privatenumber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-15T15:35:21.000Z","updated_at":"2023-09-21T02:18:00.000Z","dependencies_parsed_at":"2022-09-14T19:41:48.061Z","dependency_job_id":null,"html_url":"https://github.com/privatenumber/vue-vnode-syringe","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Fvue-vnode-syringe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Fvue-vnode-syringe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Fvue-vnode-syringe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/privatenumber%2Fvue-vnode-syringe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/privatenumber","download_url":"https://codeload.github.com/privatenumber/vue-vnode-syringe/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244717085,"owners_count":20498279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attributes","event-listeners","merge","mutate","overwrite","props","slot","vnode","vnode-syringe","vue"],"created_at":"2024-10-11T00:45:39.739Z","updated_at":"2025-03-21T00:30:23.925Z","avatar_url":"https://github.com/privatenumber.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# :syringe: vNode Syringe [![Latest version](https://badgen.net/npm/v/vue-vnode-syringe)](https://npm.im/vue-vnode-syringe) [![Monthly downloads](https://badgen.net/npm/dm/vue-vnode-syringe)](https://npm.im/vue-vnode-syringe) [![Install size](https://packagephobia.now.sh/badge?p=vue-vnode-syringe)](https://packagephobia.now.sh/result?p=vue-vnode-syringe) [![Bundle size](https://badgen.net/bundlephobia/minzip/vue-vnode-syringe)](https://bundlephobia.com/result?p=vue-vnode-syringe)\n\nAdd _attributes_ and _event-listeners_ to `\u003cslot\u003e` content.\n\nSupports `key`, `class`/`style`, `attrs`, `props` \u0026 `listeners`!\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv\u003e\n        \u003cvnode-syringe\n            class=\"new-class\"\n            @click=\"handleClick\"\n        \u003e\n            \u003cslot /\u003e   ⬅ The class and event-listener gets added to every element passed in\n        \u003c/vnode-syringe\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n\n## 🙋‍♂️ Why?\n- **🔥 Set or overwrite attributes \u0026 event-listeners** on content received from the `\u003cslot\u003e`!\n- **🧠 Smart merging strategies** Pick between merging, overwriting, or falling-back!\n- **🐥 Tiny** `1.05 KB` minzipped!\n\n## 🚀 Install\n```sh\nnpm i vue-vnode-syringe\n```\n\n## 💠 Merging strategies\n\n### Fallback\nThis is the _default behavior_. The class `new-class` and event-listener `newOnClick` only gets added if there isn't one added yet.\n\n```html\n\u003cvnode-syringe\n    class=\"new-class\"\n    @click=\"newOnClick\"\n\u003e\n    \u003cslot /\u003e\n\u003c/vnode-syringe\u003e\n```\n\nFor example, given the following `\u003cslot\u003e` content, only the event-listener `newOnClick` will be added:\n\n```html\n\u003cdiv\n\tclass=\"some-class\"\n\t\u003c!-- @click=\"newOnClick\" gets added --\u003e\n\u003e\n    some content\n\u003c/div\u003e\n```\n\n### Overwrite `!`\nAdd `!` at the end of the attribute or event-listener to overwrite what exists.\n\n```html\n\u003cvnode-syringe\n    class!=\"new-class\"\n    @click!=\"newOnClick\"\n\u003e\n    \u003cslot /\u003e\n\u003c/vnode-syringe\u003e\n```\n\nFor example, given the following `\u003cslot\u003e` content, both the class and event-listener will _overwrite_ the existing class and event-listener.\n\n```html\n\u003cdiv\n    class=\"some-class\" \u003c!-- becomes \"new-class\" --\u003e\n    @click=\"existing\" \u003c!-- becomes \"newOnClick\" --\u003e\n\u003e\n    some content\n\u003c/div\u003e\n```\n\n### Merge `\u0026`\nAdd `\u0026` at the end of the attribute or event-listener to merge with what exists.\n\n```html\n\u003cvnode-syringe\n    class\u0026=\"new-class\"\n    @click\u0026=\"newOnClick\"\n\u003e\n    \u003cslot /\u003e\n\u003c/vnode-syringe\u003e\n```\n\nFor example, given the following `\u003cslot\u003e` 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.\n\n```html\n\u003cdiv\n    class=\"some-class\" \u003c!-- becomes \"some-class new-class\" --\u003e\n    @click=\"existing\" \u003c!-- becomes \"existing(); newOnClick()\" --\u003e\n\u003e\n    some content\n\u003c/div\u003e\n```\n\n## 👨🏻‍🏫 Examples\n\n\u003cdetails\u003e\n    \u003csummary\u003e\n        \u003cstrong\u003eDemo 1:\u003c/strong\u003e Passing down attributes\n        \u003ca href=\"https://jsfiddle.net/hirokiosame/k4wyuq9o/\"\u003e\u003cimg align=\"center\" src=\"https://img.shields.io/badge/JSFiddle-Open%20Demo-blue/?logo=jsfiddle\u0026logoColor=lightblue\"\u003e\u003c/a\u003e\n    \u003c/summary\u003e\n\n\u003cbr\u003e\n\nIn this demo, the `class=\"button-group__button\"` attribute is passed down to all of its `\u003cslot\u003e` content.\n\n_ButtonGroup.vue_\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv class=\"button-group\"\u003e\n        \u003cvnode-syringe\n            class=\"button-group__button\"\n        \u003e\n            \u003cslot /\u003e\n        \u003c/vnode-syringe\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cstyle scoped\u003e\n.button-group { ... }\n.button-group__button { ... }\n\u003c/style\u003e\n```\n\n_Usage.vue_\n\n```html\n\u003cbutton-group\u003e\n    \u003cbutton\u003eButton 1\u003c/button\u003e \u003c!-- Will render with the `button-group__button` class --\u003e\n    \u003cbutton\u003eButton 2\u003c/button\u003e \u003c!-- Will render with the `button-group__button` class --\u003e\n    \u003cbutton\u003eButton 3\u003c/button\u003e \u003c!-- Will render with the `button-group__button` class --\u003e\n\u003c/button-group\u003e\n```\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n    \u003csummary\u003e\n        \u003cstrong\u003eDemo 2:\u003c/strong\u003e Merging and Overwriting classes\n        \u003ca href=\"https://jsfiddle.net/hirokiosame/9qpygc8w/\"\u003e\u003cimg align=\"center\" src=\"https://img.shields.io/badge/JSFiddle-Open%20Demo-blue/?logo=jsfiddle\u0026logoColor=lightblue\"\u003e\u003c/a\u003e\n    \u003c/summary\u003e\n\n\u003cbr\u003e\n\nBy 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  `\u0026` (merge) or `!` (overwrite) suffix.\n\n_ButtonGroup.vue_\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv class=\"button-group\"\u003e\n        \u003cvnode-syringe\n\n            \u003c!-- Merge with existing class --\u003e\n            class\u0026=\"button-group__button\"\n\n            \u003c!-- Force all buttons to have type=\"button\" --\u003e\n            type!=\"button\"\n\n            \u003c!-- Only gets added if child doesn't specify `disabled` --\u003e\n            :disabled=\"disabled\"\n        \u003e\n            \u003cslot /\u003e\n        \u003c/vnode-syringe\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nexport default {\n    props: {\n        disabled: Boolean\n    }\n};\n\u003c/script\u003e\n\n\u003cstyle scoped\u003e\n.button-group { ... }\n.button-group__button { ... }\n\u003c/style\u003e\n```\n\n_Usage.vue_\n\n```html\n\u003cbutton-group disabled\u003e\n    \u003cbutton\n\n         \u003c!-- Gets overwritten to button button-group__button --\u003e\n        class=\"button\"\n\n        \u003c!-- Gets overwritten to type=\"button\" --\u003e\n        type=\"submit\"\n\n        \u003c!-- Will be inherit parent's disabled state --\u003e\n    \u003e\n        Button 1\n    \u003c/button\u003e\n\n    \u003cbutton\n         \u003c!-- Gets overwritten to button button-group__button --\u003e\n        class=\"button\"\n\n        \u003c!-- Won't inherit parent's disabled state --\u003e\n        :disabled=\"false\"\n    \u003e\n        Button 2\n    \u003c/button\u003e\n\u003c/button-group\u003e\n```\n\u003c/details\u003e\n\n## 💁‍♀️ FAQ\n### How can I add attributes/event-listeners to a specific element in the `\u003cslot\u003e`?\n\nYou can use [Subslot](https://github.com/privatenumber/vue-subslot) to pick out specific elements in the slot.\n\nFor example, if you only want to accept `\u003cbutton\u003e`s in your slot:\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv class=\"button-group\"\u003e\n        \u003cvnode-syringe\n            class\u0026=\"button-group-item\"\n            @click=\"onClick\"\n        \u003e\n            \u003csubslot element=\"button\" /\u003e\n        \u003c/vnode-syringe\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport Subslot from 'vue-subslot';\nimport vnodeSyringe from 'vue-vnode-syringe';\n\nexport default {\n    components: {\n        Subslot,\n        vnodeSyringe\n    },\n\n    ...,\n\n    methods: {\n        onClick() {\n            ...\n        }\n    }\n};\n\u003c/script\u003e\n```\n\n## 👨‍👩‍👧 Related\n- [vue-proxi](https://github.com/privatenumber/vue-proxi) - 💠 Tiny proxy component\n- [vue-subslot](https://github.com/privatenumber/vue-subslot) - 💍 Pick 'n choose what you want from a slot passed into your Vue component\n- [vue-pseudo-window](https://github.com/privatenumber/vue-pseudo-window) - 🖼 Declaratively interface window/document in your Vue template\n- [vue-v](https://github.com/privatenumber/vue-v) - render vNodes via component template\n- [vue-frag](https://github.com/privatenumber/vue-frag) - 🤲 Directive to return multiple root elements\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprivatenumber%2Fvue-vnode-syringe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprivatenumber%2Fvue-vnode-syringe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprivatenumber%2Fvue-vnode-syringe/lists"}