Pass Svelte Component as Props

Viewed 3498

I am pretty new to the svelte environment, I have some react code and try to convert them as svelte for the learning purpose.

In the react, we can pass a string or React Node as props.

<TabPane
name="profile"
title={<img src="images/profile.svg" alt="Profile" />}
key="1"
>
    {/** some code **/} 
</TabPane>

I am trying to use the same code in svelte, but it throws an error. enter image description here

2 Answers

Yes, you can't do this in Svelte.

You'll have to figure out how you can achieve the same outcome with the APIs available in Svelte.

For example, you can use <slot>:

<TabPane
  name="profile"
  key="1"
>
  <img slot="title" src="images/profile.svg" alt="Profile" />
  <!-- some code, eg: -->
  <div>Some code here</div>
</TabPane>
<!-- filename: TabPane.svelte -->

<h1>
  <slot name="title" />
</h1>

<slot />

The element with attribute slot="title" will be inserted into <slot name="title">

and the rest of the elements will be inserted into <slot />


This is equivalent in React:

function TabPane({ title, children }) {
  return (
    <>
       <h1>{title}</h1>
       {children}
    </>
  );
}

If you want to pass in only string for the title, you could wrap the string around with <svelte:fragment> so that you can add the slot="title" attribute

<TabPane
  name="profile"
  key="1"
>
  <svelte:fragment slot="title">
    string title here
  <svelte:fragment>
  <!-- some code, eg: -->
  <div>Some code here</div>
</TabPane>

Reference:

In many cases you'll want to use slots as Tan Li Hau suggested. However, it is possible to pass components as props. For this, we are going to make use of <svelte:component>. It's quite restrictive, but it's a possibility.

https://svelte.dev/docs#svelte_component

<svelte:component>

Normally, you'd use <svelte:component> like this:

<script>
  import Component from './component.svelte'
</script>

<svelte:component this={Component} foo={bar} />

The above is equivalent to this:

<script>
  import Component from './component.svelte'
</script>

<Component foo={bar} />

Passing down components through props

This means we can actually pass down components through props.

<!-- app.svelte -->

<script>
  import ComponentA from './component-a.svelte'
  import ComponentB from './component-b.svelte'
</script>

<ComponentA foo={ComponentB} />

And render the component…

<!-- component-a.svelte -->

<script>
  export let foo
</script>

<svelte:component this={foo} />

Caveats

Note there are a few things you can't do:

  • Set props on the component passed down through props
  • Pass down components which children through props
  • Or do pretty much anything else with the component passed down as a prop

Svelte may not even be designed to do this (even though it works). So yeah, unless you really need this, use slots. But now you know this is possible.

Related