1

In react we can do

<SomeListComponent>
  <SomeListComponent.Item /> // Like this
</SomeListComponent>

is there a svelte equivalent of dot notation like in react?

3 Answers 3

3

This actually does seem to be possible, currently. You can accomplish this by defining individual components in individual files. Then, in a barrel file do the following:

  1. Import the primary component and all the necessary parts.
  2. Attach all the necessary piecewise components to the primary component as object properties.
  3. Re-export the primary component alone.

I'm assuming you'd be working with barrel files anyway in this scenario since Svelte doesn't support multiple components in a single file like React (at least not at the time of this writing).

Dot Notation Example


Another option -- if you're trying to expose components as something strictly related to a primary component -- is to expose components through slots. You still start out by creating each of the individual components in individual files. But in the end, you expose all of the subcomponents through slot props in the primary component file instead of a barrel file.

Example Exposing Components through Slot Props


The benefit of the first approach (dot notation) is that it's familiar (thanks to React). Assuming you only perform imports from the barrel file (index.js), it'll be readily apparent what the primary component is and what the related sub components are. The disadvantage is that you can technically use the subcomponents outside the scope of the primary component. But practically speaking, it's unlikely that many people will do this, and it's not really a problem. Another potential concern is that it's awkward to add properties to imported modules.

The second approach (slot props), is a little less familiar since it's svelte-specific. But it still has the benefit of distinguishing primary components from subcomponents. As an added benefit, it also prevents the use of subcomponents outside the scope of the primary component. Finally, there are no awkward attachments to imported modules. :) However, this approach can get out of hand if you're exposing a large number of components through slot props. And, of course, it only really makes sense if you're employing slots.

A simple use case for the second approach might be modal action buttons (if you wanted to control the style of said buttons and the modal was simple).


Other options might exist. At the very least, I'm confident that there are no solutions involving local private components in the same file as the primary component (again, at the time of this writing).

3
  • I am getting some typescript errors with your first approach that I am unable to fix. Do you know how to do this with TS support? Commented Sep 21, 2022 at 16:03
  • @CraigHowell Yeah so that one's tricky because I don't know how Svelte Kit internally defines its TypeScript types. (You end up with weird things like typeof PrimaryComponent__SvelteComponent_.) So for TS, in the index.js file from my example: Instead of the 2 lines that I put at the end, you'd need to do: export default Object.assign(PrimaryComponent, { SubComponent }); Commented Sep 21, 2022 at 19:55
  • Another option is to brute force defining custom types, but that gets a little ugly. First, you'd need a custom type: type ComposedComponent = typeof PrimaryComponent & { SubComponent: typeof SubComponent };. Then, you'd set the property of the PrimaryComponent with dot notation: (PrimaryComponent as ComposedComponent).SubComponent = SubComponent;. Finally, you'd export the PrimaryComponent with its type coerced again: export default PrimaryComponent as ComposedComponent;. Way more verbose, but in some cases it prevents weird behaviors during HMR (at least that's the case in React). Commented Sep 21, 2022 at 20:06
1

Nope.

Unwrap it:

<script>
  ...
  const { Item } = SomeListComponent
</script>

<SomeListComponent>
  <Item />
</SomeListComponent>

Note, also, that the component name must be capitalized (<Item />, not <item /> -- or Svelte would consider it's a DOM element).

1

The answer given here worked fine for javascript, but failed for typescript. Here is another method that makes this typescript compatible.

Example module structure:

space/
 Compact.svelte
 index.ts
 Space.svelte

You can make the components you want in isolation in each of their own files. The magic sauce is having an index.ts file where you rebuild the components in a custom class.

index.ts

import SpaceComponent from './Space.svelte';
import CompactComponent from './Compact.svelte';

export class Space extends SpaceComponent
{
    static Compact = CompactComponent;
}

App.svelte exampe

<script lang="ts">
import { Space, Button } from './svelte-antd'

const onButtonClick = () => { console.log('button clicked!'); }

</script>

<main style="width: 100vw; height: 100vh;padding: 5px;">
  <Space wrap={true} size={30}>
    <Button type="primary" on:click={onButtonClick}>Primary Button</Button>
    <Space.Compact>
      <Button type="default" shape="round" on:click={onButtonClick}>Default Button</Button>
      <Button type="dashed" shape="circle" on:click={onButtonClick}>Dashed Button</Button>
    </Space.Compact>  
  </Space>
</main>

Not the answer you're looking for? Browse other questions tagged or ask your own question.