carbon-design-system / carbon-components-svelte

Svelte implementation of the Carbon Design System
https://svelte.carbondesignsystem.com
Apache License 2.0
2.71k stars 262 forks source link

Tabs `selected` index will desync when adding/removing tabs dynamically #1537

Open brunnerh opened 2 years ago

brunnerh commented 2 years ago

Tabs/contents are never removed from the Tabs context and DOM order is not considered when determining the index, so if a tab is removed and added back in, it will have a higher/different index than before.

E.g.

<Tabs bind:selected={selectedTabIndex}>
  {#if showTab1}
      <Tab label="Tab 1"/>
  {/if}
  <Tab label="Tab 2"/>
  <Tab label="Tab 3"/>
  <div slot="content">
      {#if showTab1}
          <TabContent>
              Tab 1 Content
          </TabContent>
      {/if}
      <TabContent>
          Tab 2 Content
      </TabContent>
      <TabContent>
          Tab 3 Content
      </TabContent>
  </div>
</Tabs>

REPL

After toggling the boolean showTab1 off and on the index of the first tab will have gone from 0 to 3. This could cause issues when trying to select a specific tab or trying to identify which tab is selected.

A possible fix might be to:

(A different selection method based on explicit keys/IDs would also be helpful. Though this would not prevent the potential confusion caused by this issue.)

metonym commented 2 years ago

Previous issues: #368, #1493

The workaround is to wrap dynamic Tabs in a #key block (#438, https://github.com/carbon-design-system/carbon-components-svelte/discussions/1494#discussioncomment-3717572).

The "Svelte way" would be to avoid composition/context and use consumer-provided keys to track the tabs (#435).

brunnerh commented 2 years ago

@metonym Using #key is not ideal if the tabs contain a lot/complex content.

A solution using keys should not be too complicated, it could also use slot props like the DataTable. Are there any plans to revive the keyed approach?