Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/privatenumber/vue-frag
🤲 Create Fragments (multiple root-elements) in Vue 2
https://github.com/privatenumber/vue-frag
component directive fragment multiple nodes root ssr vue vuejs
Last synced: 6 days ago
JSON representation
🤲 Create Fragments (multiple root-elements) in Vue 2
- Host: GitHub
- URL: https://github.com/privatenumber/vue-frag
- Owner: privatenumber
- License: mit
- Created: 2020-09-08T22:02:12.000Z (over 4 years ago)
- Default Branch: develop
- Last Pushed: 2023-08-11T12:31:18.000Z (over 1 year ago)
- Last Synced: 2024-05-04T00:17:54.130Z (10 months ago)
- Topics: component, directive, fragment, multiple, nodes, root, ssr, vue, vuejs
- Language: TypeScript
- Homepage:
- Size: 741 KB
- Stars: 214
- Watchers: 3
- Forks: 14
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Use [Vue 3's Fragment feature](https://v3.vuejs.org/guide/migration/fragments.html) in Vue 2 to return multiple root elements.
```vue
⬅ This root element will not exist in the DOM
import { Fragment } from 'vue-frag'
export default {
components: {
Fragment
}
}
```
👉 [Try it out on CodePen](https://codepen.io/hirokiosame/pen/PoNVZbV)!
### Features
- **✅ Multiple root nodes** Without creating a functional component!
- **🔥 SSR** Unwraps the root element on client-side post-hydration!
- **⚡️ Directives** Supports `v-if`, `v-for`, and `v-html`!
- **👩🔬 Battle-tested** Checkout the tests [here](/test/)!
🔥 Pro-tip
Want to be able to just have multiple root-nodes in your SFC without a wrapper?
Use vue-frag-plugin to automatically inject vue-frag so that you can return multiple root nodes without a fragment component!
## 🚀 Install
```sh
npm i vue-frag
```
## 🚦 Quick Setup
You can either choose to use the _Component_ or _Directive_ API.
### Component API
The Component API is designed to be used at the root of the template. It should feel intuitive to use and cover most use-cases.
Import `Fragment` and use it as the root element of your component:
```vue
Hello world!
import { Fragment } from 'vue-frag'
export default {
components: {
Fragment
}
}
```
#### Register globally
[Globally registering](https://vuejs.org/v2/guide/components-registration.html) the component lets you use it without needing to import it every time.
```js
import { Fragment } from 'vue-frag'
Vue.component('Fragment', Fragment)
```
### Directive API
Use the Directive API to have more nuanced control over placement. For example, if you want to unwrap the root node of a component on the usage-end.
The Component API uses the Directive API under the hood.
```vue
Hello world!
import frag from 'vue-frag'
export default {
directives: {
frag
}
}
```
#### Register globally
Make it available anywhere in your Vue application.
```js
import frag from 'vue-frag'
Vue.directive('frag', frag)
```
## 👨🏻🏫 Examples
#### Returning multiple root nodes
Component API
```html
{{ i }}
```
Directive API
```html
{{ i }}
```
#### Unwrapping the root node from a component
Use the Directive API to unwrap the root node of a component.
```html
```
#### Supports v-if too
```html
Hello world!
```
#### Access fragment DOM nodes
```vue
Hello world
export default {
mounted() {
console.log(this.$el.frag)
}
}
```
## 💁♀️ FAQ
### When would I want to return multiple root nodes?
Whenever you feel like the root-element of your component adds no value and is unnecessary, or is messing up your HTML output. This usually happens when you want to return a list of elements like `
In Vue 2, it's possible to return multiple nodes with a [Functional Component](https://vuejs.org/v2/guide/render-function.html#Functional-Components) but functional components are stateless (no `data()` or [life-cycle hooks](https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram)), doesn't support `methods`, doesn't have very good template support, and can lead to SSR bugs (eg. mismatching nodes).
Related VueJS Issues / Stackoverflow Qs:
- [vuejs/vue #7088](https://github.com/vuejs/vue/issues/7088)
- [vuejs/vue #7606](https://github.com/vuejs/vue/issues/7606)
- [Stackoverflow: A way to render multiple root elements in VueJS?](https://stackoverflow.com/questions/47511674/a-way-to-render-multiple-root-elements-on-vuejs-with-v-for-directive)
### How does this work?
vue-frag works by tricking Vue.js to think that the root element is still in the DOM, when it's actually not.
When vue-frag is applied to an element, it uses the [`inserted` directive hook](https://vuejs.org/v2/guide/custom-directive.html#Hook-Functions) to swap the element out with its children to remove itself from the DOM. It then patches surrounding DOM nodes (eg. parent, sibling, children) to make them think that the element is still in the DOM.
Here are all the DOM APIs Vue.js uses that are patched:
- [`insertBefore()`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L5748)
- [`removeChild()`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L5752)
- [`appendChild()`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L5756)
- [`hasChildNodes()`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L6427)
- [`parentNode`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L5760)
- [`nextSibling`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L5764)
- [`firstChild`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L6447)
- [`childNodes`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L7667)
- [`innerHTML`](https://github.com/vuejs/vue/blob/531b7619b137aecd71441e1ea53dae3066d71bc8/dist/vue.js#L6431)
### Does `v-show` work?
[Like in Vue 3](https://jsfiddle.net/hirokiosame/pebL1cdx/), `v-show` does not work on components that return a fragment. `v-show` works by setting `style="display: none"` on the root element of the target component. With vue-frag removing the root element, there would be no grouping-element to apply the `display: none` to. If the fragment returned elements, it's possible to apply it to each child-node, but it's possible for them to be text-nodes which cannot be styled.
## 👨👩👧 Related
- [vue-frag-plugin](https://github.com/privatenumber/vue-frag-plugin) - Build-time plugin to seamlessly use multiple root nodes
- [vue-subslot](https://github.com/privatenumber/vue-subslot) - 💍 pick out specific elements from component ``s
- [vue-vnode-syringe](https://github.com/privatenumber/vue-vnode-syringe) - 🧬 Add attributes and event-listeners to `` content 💉
- [vue-proxi](https://github.com/privatenumber/vue-proxi) - 💠 Tiny proxy component
- [vue-pseudo-window](https://github.com/privatenumber/vue-pseudo-window) - 🖼 Declaratively interface window/document in your Vue template
- [vue-v](https://github.com/privatenumber/vue-v) - render vNodes via component template
## Sponsors