Skip to content

Commit

Permalink
Move the portal root to the bottom of the target after initial render
Browse files Browse the repository at this point in the history
Fixes #78
  • Loading branch information
rgossiaux committed Mar 7, 2022
1 parent 3014990 commit fada4f2
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/lib/components/portal/portal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { render } from "@testing-library/svelte";
import Portal from "./Portal.svelte";
import PortalGroup from "./PortalGroup.svelte";
import { click } from "$lib/test-utils/interactions";
import { tick } from "svelte";

function getPortalRoot() {
return document.getElementById('headlessui-portal-root')!
Expand Down Expand Up @@ -333,3 +334,26 @@ it('should cleanup the Portal properly when Svelte would not detach it', async (
expect(getPortalRoot()).not.toBe(null)
expect(getPortalRoot().childNodes).toHaveLength(1)
})

it('should move the Portal last during initial render', async () => {
expect(getPortalRoot()).toBe(null)

// We need to use a custom target because of the implementation of
// render() in the testing library
render(svelte`
<script>
let target = document.body.firstChild;
</script>
<PortalGroup {target}>
<Portal>Portal</Portal>
</PortalGroup>
<main>Main</main>
`)

await tick();

expect(document.body.innerHTML).toMatchInlineSnapshot(
`"<div> <main>Main</main><div>Portal</div></div>"`
)
})
11 changes: 11 additions & 0 deletions src/lib/hooks/use-portal.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { tick } from "svelte";

export function portal(
element: HTMLElement,
target: HTMLElement | null | undefined
) {
if (target) {
target.append(element);
// During initial render, the "portal" might be constructed before
// the root component has even attached, causing the portal to not work.
// This is a workaround for this issue--it can't guarantee the portal is
// **always** last, but it should catch the normal cases.
tick().then(() => {
if (target && element !== target.lastChild) {
target.appendChild(element);
}
});
}
return {
update(newTarget: HTMLElement) {
Expand Down

1 comment on commit fada4f2

@vercel
Copy link

@vercel vercel bot commented on fada4f2 Mar 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.