Synced tabs #953
Replies: 7 comments 4 replies
-
Any thoughts on tab-syncing being the default option? Use the tab label prop and if a tab is switched, switch any other tabs that share that same label. You can have a bool to opt-out of this default behaviour. Another option could be to derive a key from all the labels used within a For example you have a No idea is these are good ideas instead of requiring opt-in, but figured I'd throw them out there 😊 |
Beta Was this translation helpful? Give feedback.
-
Did not think of that, thanks for sharing. I usually prefer to opt-in to feature but in this case, I don't think I can think of some bad side effects, specially if you can opt out (I imagine these cases would be rare) 🤔 Maybe some other people have some ideas or reasons why it should be or not be the default? |
Beta Was this translation helpful? Give feedback.
-
Coming from the world of MyST markdown and sphinx-design, I would personally prefer opting in with a specific :::{tab-set-code}
```json
{
"total": 1,
"page": 1,
"per_page": 5,
"subscriptions": [
{
"feed_url": "https://example.com/rss1",
"guid": "64c1593b-5a1e-4e89-b8a3-d91501065e80",
"is_subscribed": true,
"guid_changed": "2022-12-23T10:24:14.670Z",
"new_guid": "36a47c4c-4aa3-428a-8132-3712a8422002"
}
]
}
```
```xml
<?xml version="1.0" encoding="UTF-8"?>
<subscriptions>
<total>1</total>
<page>1</page>
<per_page>5</per_page>
<subscription>
<feed_url>https://example.com/rss1</feed_url>
<guid>64c1593b-5a1e-4e89-b8a3-d91501065e80</guid>
<is_subscribed>true</is_subscribed>
<guid_changed>2022-12-23T10:24:14.670Z</guid_changed>
<new_guid>36a47c4c-4aa3-428a-8132-3712a8422002</new_guid>
</subscription>
</subscriptions>
```
:::
This would generate a set of tabs that have ::::{tab-set}
:::{tab-item} JSON
:sync: tabcode-json
```bash
curl --location '/subscriptions' \
--header 'Content-Type: application/json' \
--data '{
"subscriptions": [
{
"feed_url": "https://example.com/feed1"
},
{
"feed_url": "https://example.com/feed2"
},
{
"feed_url": "https://example.com/feed3"
},
{
"feed_url": "example.com/feed4",
"guid": "2d8bb39b-8d34-48d4-b223-a0d01eb27d71"
}
]
}'
```
:::
:::{tab-item} XML
:sync: tabcode-xml
```bash
curl --location '/subscriptions' \
--header 'Content-Type: application/xml' \
--data '<?xml version="1.0" encoding="UTF-8"?>
<subscriptions>
<subscription>
<feed_url>https://example.com/feed1</feed_url>
</subscription>
<subscription>
<feed_url>https://example.com/feed2</feed_url>
</subscription>
<subscription>
<feed_url>https://example.com/feed3</feed_url>
</subscription>
<subscription>
<feed_url>example.com/feed4</feed_url>
<guid>2d8bb39b-8d34-48d4-b223-a0d01eb27d71</guid>
</subscription>
</subscriptions>'
```
:::
:::: |
Beta Was this translation helpful? Give feedback.
-
Thanks for the super detailed write-up @HiDeoo! I like all the ideas here I think. I’d be plus one on something like I wrote a tiny “atom” store while working on the theme editor id that could be helpful? starlight/docs/src/components/theme-designer/atom.ts Lines 1 to 20 in d7f2ab4 But I’m also fine with whatever solution you think feels best — keeping it in the tabs class is fine by me! Re: testing — some testing would indeed be cool. I don’t have strong opinions here. The drawback of only testing the custom element code with Vitest and a browser environment would be that we aren’t testing the markup generated by the Astro component, so could only give us a certain amount of confidence. We could also wait it out as PRs like withastro/astro#7979 will start to bring better testing support for Astro stuff closer too I’d say. |
Beta Was this translation helpful? Give feedback.
-
I'm sry to be little impatient and hyped at the same time, but are there any updates regarding this topic? |
Beta Was this translation helpful? Give feedback.
-
Should tab selection be preserved across page navigation? Across sessions? |
Beta Was this translation helpful? Give feedback.
-
Noting that synced tabs was released in Starlight v0.22 — thanks very much to @HiDeoo for the hard work putting it together 🎉 |
Beta Was this translation helpful? Give feedback.
-
What version of
starlight
are you using?0.6.1
What is your idea?
This proposal is a follow-up on a Discord discussion about the addition of synced tabs to Starlight.
Why is this feature necessary?
This features is pretty useful to show tabular data where the user will benefit from having the tabs synced. e.g.:
Do you have examples of this feature in other projects?
pnpm
package manager tab in the step 1, the step 2 command will be updated to show thepnpm
command.astro.mp4
firebase.mp4
starlight-package-managers.mp4
API
I like the Astro docs current approach of basically passing a basic string to the
<Tabs />
component when you want to sync the tabs. This is a very simple API and it is easy to understand what is going on imo.Altho, I am personally not a huge fan of the
sharedStore
prop name currently used. It kinda feels like it is leaking some implementation details and not super obvious it's related to syncing the tabs. I would prefer something likesync
orsyncKey
for example.Any other ideas for the end user API?
Implementation
The Astro current implementation is using a Preact component with a hook to handle the sync which relies on Nano Stores to sync some state between the tabs. I would assume this is an approach we would want to avoid in Starlight as it would add some dependencies and one UI framework.
My component
starlight-package-managers
is using someMutationObserver
to detect tab changes and update the selected tab accordingly. This choice is mostly due to the fact that I am doing that outside of Starlight and it is not a good choice for Starlight itself.@delucis mentioned using a simple store primitive that each tabs instance subscribes to and updates from. This is a solid idea, we could expose a relatively small
createStore()
function returning a store with various methods likestore.getState()
,store.subscribe()
andstore.setState()
for example. Later down the line we could even imagine some other components re-using this store primitive to sync some other state (altho I don't see an example right now).Altho, after thinking about it for a bit, I wonder if right now, the simplest approach would not be to shove everything in the existing
StarlightTabs
component as I don't think we need that much to implement this feature. We could have a static property with a record of all the tabs instances initialized with a sync key keyed by these keys and a static method which would be called when a new tab is selected that would update the selected tab for all the tabs instances with the same sync key.A quick diff could look like this (note that is a very rough draft, not properly written or thought, tested or anything):
Any thoughts on this? Some other ideas?
Testing
If I am not mistaken, we are currently not testing any of the Starlight components. Do we want to add tests for this? If yes, what approach would we want to take? Spinning up something like Playwright to test the components in a browser could add a lot of confidence in this but may feels a bit too much just for this feature. Another approach as we are using vitest already could be switching the test environment from
node
tohappy-dom
for example for a new set of tests, extract the web component from the Astro component (likeStarlightTOC
) and figure out how to test it using happy-dom. I have never done that for web components but I would assume it is possible. Any thoughts on this?Other
Did I miss anything? ^^
Participation
Beta Was this translation helpful? Give feedback.
All reactions