Svelte: Replace target instead of appending to it

Created on 16 Jun 2018  Â·  9Comments  Â·  Source: sveltejs/svelte

Hi, when I do new MyComponent({target: document.getElementById('someId')}) then the new component gets added to the element instead of replacing it.

I would love to have a way to replace the target, f.x new MyComponent({target: document.getElementById('someId'), replace: true}). This would give my users a better experience in situations where I'm adding Svelte components to content that they already see in their browser.

Most helpful comment

That's not quite true — there is an API for slots, though I think we haven't got round to documenting it. You can do this:

const thing = new Thing({
  target,
  slots: {
    default: someDomNodeOrFragment,
    foo: someOtherDomNodeOrFragment
  }
});

If you're compiling your components with hydratable: true and instantiating them with hydrate: true, it will reuse whatever DOM is currently in the target (and discard the rest). This is designed for rehydrating server-rendered components, so if that's what your goal is then it's what I'd recommend.

Otherwise, using a helper to clear out the existing DOM is the best way forward — it's not something we should add to Svelte itself, since it's extra code for something that most people won't need.

All 9 comments

This conversation may still be relevant.

https://github.com/sveltejs/svelte/issues/537

function mountReplace(Component, options) {
    const frag = document.createDocumentFragment();
    const component = new Component({ ...options, target: frag });

    options.target.parentNode.replaceChild(frag, options.target);

    return component;
}

// usage
mountReplace(MyComponent, { target, data });

Also I didn't tested the latest version but the last time I tried I couldn't render the target content as a default <slot> in my component. I expect all children in a target DOM to become children of my component in a slotted spot.

This is a funny one :) I ran into this while trying to set up hot reloading for svelte.

The slot functionality relies on you being in the Svelte context. So you will need to wrap your component that contains the slot in a small svelte "app" and mount that.

That's not quite true — there is an API for slots, though I think we haven't got round to documenting it. You can do this:

const thing = new Thing({
  target,
  slots: {
    default: someDomNodeOrFragment,
    foo: someOtherDomNodeOrFragment
  }
});

If you're compiling your components with hydratable: true and instantiating them with hydrate: true, it will reuse whatever DOM is currently in the target (and discard the rest). This is designed for rehydrating server-rendered components, so if that's what your goal is then it's what I'd recommend.

Otherwise, using a helper to clear out the existing DOM is the best way forward — it's not something we should add to Svelte itself, since it's extra code for something that most people won't need.

OK, that's super useful. Thanks for setting me straight. Sorry @constgen for poor information.

Closing this, as I don't think there's anything else that needs to happen. Comment if you think otherwise.

@Conduitry maybe add a note containing the mountReplace function above in the docs?

For future reference.

there is an API for slots

Seems like this API was for Svelte v2.
For v3, there is this open PR and this issue which mentions a workaround using the private API.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

noypiscripter picture noypiscripter  Â·  3Comments

1u0n picture 1u0n  Â·  3Comments

clitetailor picture clitetailor  Â·  3Comments

mmjmanders picture mmjmanders  Â·  3Comments

bestguy picture bestguy  Â·  3Comments