Home > OS >  React Components to SvelteKit - Objects with HTML in attribute (JSX rendering) to Script tag
React Components to SvelteKit - Objects with HTML in attribute (JSX rendering) to Script tag

Time:05-04

Since I'm changing a React project to SvelteKit, I've got a specific situation that made me a lot curious about it.

Let's suppose that I do have a component in React that receives the object columnsMockExample as props, for example, and consumes an HTML inside of the object, as:

const columnsMockExample = [{name: 'Column 1', html: '<div>Inner HTML example</div>' }]
<ColumnsComponent columnsProp={columnsMockExample}/>

So, in React, we could map this object to consume it and show every .html inside of columnsMockExample:

{props.columnsProp.map((columnFromMockExample) => columnFromMockExample.html)};

So then, here is the question: as SvelteKit has the <script/> tag apart from the HTML, how can I create my object columnsMockExample inside of the SvelteKit<script/> tag since it is not JSX?

wrong SvelteKit script example is written below:

<script> 
  const columnsMockExample = [{name: 'Column 1', html: '<div>Inner HTML example</div>' }] 
</script>

Thank you.

CodePudding user response:

There are several different approaches that can be taken here, all of which are a bit different.

  1. Use slots to make each column render a cell and render entire rows via the parent components slot. Example can be seen in this question.

  2. Define separate components and instead of passing HTML, you pass the component class. As of now this is a bit of a pain, because components cannot be defined in the same file. REPL example

    The key is to render the components dynamically via <svelte:component /> and pass in the current column value as a well-known prop that is the same for all cell components.

  3. Instead of using components actually render HTML directly using {@html}. I do absolutely not recommend this, because it makes it easy to create XSS vulnerabilities. REPL example

    The key here is to provide the content as a function of the column value, like this:

     const columns = [
         { key: 'name', html: value => `<button>${value}</button>` },
         { key: 'age', html: value => `<em>${value}</em>` },
     ]
    

    So this can be rendered with the current value like this:

    <td>{@html column.html(value)}</td>
    

    If you only have static content, you do not need a function of course.

  4. Use slots and keys to render the different cells. This is a very flexible approach which is used e.g. by the DataTable of the Carbon Svelte components.

    The columns define the key, and the cells can be templated via slots and slot props.

    E.g.

    <!-- DataTable.svelte -->
     <script>
         export let columns;
         export let rows;
     </script>
    
     <table>
         {#each rows as row}
             <tr>
                 {#each columns as column}
                     {@const value = row[column.key]}
                     <td>
                         <slot {value} key={column.key} />
                     </td>
                 {/each}
             </tr>
         {/each}
     </table>
    

    Usage example:

     <script>
         import DataTable from './DataTable.svelte';
         const rows = [
             { name: 'John', age: 64 },
             { name: 'Jane', age: 46 },
         ]
         const columns = [
             { key: 'name' },
             { key: 'age' },
         ]
     </script>
    
     <DataTable {columns} {rows} let:key let:value>
         {#if key == 'name'}
             <button>{value}</button>
         {:else}
             {value} <!-- Fallback to just the cell content -->
         {/if}
     </DataTable>
    

    REPL

CodePudding user response:

If it's pure HTML (no Svelte-specific code, just raw HTML), you can use the @html directive:

<script> 
  const columnsMockExample = [{name: 'Column 1', html: '<div>Inner HTML example</div>' }] 
</script>

{#each columnsMockExample as example}
  {@html example.html}
{/each}

Docs: https://svelte.dev/docs#template-syntax-html

If there's Svelte components or click handlers etc in there, that doesn't work though. In that case you need to rewrite the code using components and slots (https://svelte.dev/docs#template-syntax-slot) and/or the svelte:component tag (https://svelte.dev/docs#template-syntax-svelte-component) - how exactly depends on what your goal is.

  • Related