Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEXT: Review options for sharing and maintaining common component data between frameworks #2811

Open
endigo9740 opened this issue Aug 13, 2024 · 1 comment
Assignees
Labels
administration Items related to the project but outside the code.

Comments

@endigo9740
Copy link
Contributor

endigo9740 commented Aug 13, 2024

Following our recent integration of Zag.js, we're now unifying logic and state handling for most components and features using Zag itself. However, there's still a lot of repetition in how we scaffold components per each framework, including:

  1. Common prop names
  2. Common default prop values
  3. Common types and interfaces
  4. Common JSDoc comments for type definitions

We should investigate potential solutions to provide a single source of truth for this information.

Potential Issues

Hugo and I have discussed this on several occasions, but the biggest barrier of entry is that not all components are constructed symmetrically per framework. For simple components such as Avatars the implementation is quite close. The same list of props, values, types, etc:

However, this is not always the case. Select components, such as Accordions and Tabs, can differ wildly:

The most common reason for this being React (or JSX-based component systems) lacking an 1:1 equivalent for named slots. For example:

Svelte:

<Tabs bind:value={group}>
	{#snippet list()}
		<Tabs.Control value="plane">Plane</Tabs.Control>
		<Tabs.Control value="boat">Boat</Tabs.Control>
		<Tabs.Control value="car">Car</Tabs.Control>
	{/snippet}
	{#snippet content()}
		<Tabs.Panel value="plane">Plane Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="boat">Boat Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="car">Car Panel - {lorem}</Tabs.Panel>
	{/snippet}
</Tabs>

React:

<Tabs value={group} onValueChange={setGroup}>
	<Tabs.List>
		<Tabs.Control value="plane">Plane</Tabs.Control>
		<Tabs.Control value="boat">Boat</Tabs.Control>
		<Tabs.Control value="car">Car</Tabs.Control>
	</Tabs.List>
	<Tabs.Content>
		<Tabs.Panel value="plane">Plane Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="boat">Boat Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="car">Car Panel - {lorem}</Tabs.Panel>
	</Tabs.Content>
</Tabs>

While fairly similar from the end user's perspective, there's some notable differences:

  • Svelte: uses snippets for List/Control; requires only 3 components (Root, List, Panel)
  • React: requires dedicated components for each part of the component tree structure

Note that React does supply React.Node props, allowing you to pass template data through props. But the user-facing API for doing this is not widely used in any framework we've reviewed. And personally speaking is quite unfriendly:

<Tabs
	value={group}
	onValueChange={setGroup}
	list=(
		<Tabs.Control value="plane">Plane</Tabs.Control>
		<Tabs.Control value="boat">Boat</Tabs.Control>
		<Tabs.Control value="car">Car</Tabs.Control>
	)
	content=(
		<Tabs.Panel value="plane">Plane Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="boat">Boat Panel - {lorem}</Tabs.Panel>
		<Tabs.Panel value="car">Car Panel - {lorem}</Tabs.Panel>
	)
/>

This is great for small additions, such as icons. But would quickly become unmanageable once the size of the child content reached a certain length.

Potential Solutions

So far we do not have a solid solution for this scenario. However, the following ideas have been discussed:

  1. Standardize all components around the composed tree of components (ala React), unfortunately this hurts the DX for Svelte, Vue and other frameworks on both the end user and maintainer/contributor side of things. We don't get to use the handy tools they provide (Snippets, slots, etc)
  2. Keep separate structures, but find an alternative way to define the non-uniform props/types per these components. Unfortunately this returns us to the original issue we're trying to solve.

We welcome additional ideas and proposals around this in the comments section below!

@endigo9740 endigo9740 added the administration Items related to the project but outside the code. label Aug 13, 2024
@endigo9740 endigo9740 added this to the v3.0 (Next) milestone Aug 13, 2024
@endigo9740
Copy link
Contributor Author

As much as I'd like to revisit this, I think is going to have to be bumped to to a major update post-v3. Perhaps when we begin implementing our next component library?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
administration Items related to the project but outside the code.
Projects
None yet
Development

No branches or pull requests

2 participants