Recently at my day job, I encountered a very specific scenario that I wrestled with for quite a bit. I had a routed set of views, which were using a layout view template because it needed a very specific markup for positioning using CSS Grid.
The issue I had was although the route layout had a <slot></slot>
element inside of it for projecting the routes, I wanted a custom navigation element to be projected inside of the routed view. Previously there was a bit of duplication to add the custom element into the right area.
I initially tried to use router View Ports to achieve the result I needed, but they’re more designed for rendering sub-views within a view, I needed to render a component into a specific area of the page and have it react to route change events.
Then I remember the Portal attribute by core team member Binh Vo, it has actually been around for a while now. I haven’t had a need for this plugin, until now. In my situation, I needed to leverage the target property of the attribute to tell it where to inject my custom element and everything worked as expected.
My layout view simplified looks like this:
<section>
<main-nav></main-nav>
<inner-nav portal="target: #nav-slot;"></inner-nav>
<slot></slot>
</section>
For each routed view the simplified markup looks like this:
<template>
<main>
<div class="dashboard-wrapper">
<div class="inner-content">
<section>
<div id="nav-slot">
<div class="content">
<h1>Some content</h1>
</div>
<div>
</section>
</div>
</div>
</main>
</template>
When this routed view is loaded, the portal attribute will inject the element from the router layout into the DIV with the ID nav-slot
. Super simple stuff and it does exactly what I needed it to do. The portal plugin can be found on GitHub here and it’s great to see how it all functions behind-the-scenes. A demo of the plugin in action can also be found here.