-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Styling single element components while retaining element API #6882
Comments
That's one use-case I want to use declarative actions for sveltejs/rfcs#41 . Because creating wrapper components just for styling feels wrong to me.
<svelte:target class:primary />
<style>
.primary {
background: brown;
color: white;
}
</style> And then: <script>
import primary from 'styled/button/primary.svelte'
</script>
<button use:primary></button> You can't really do that with imperative actions right now because handling of |
To break this down:
|
<input {...$$props} /> <script>
import MyInput from "./MyInput.svelte"
let value
</script>
<MyInput bind:value />
I think most of the need for spreading props, handlers, bindings is on single element components. For compound components spreading is mostly an anti pattern (it makes typing, documentation and testing hard). Compound components should aim to have a narrow interface. But HTML elements start with a massive API surface area this is very hard to recreate by hand and needs a lot of knowledge. Nearly all the time what we want is just something that behaves the same as <script>
export let primary
</script>
<svelte:element
default='button'
class:primary
/>
<style>
.primary {
background: brown;
color: white;
}
</style> vs <script>
export let primary
</script>
<button
class:primary
on:*
{...$$props}
><slot/></button>
<style>
.primary {
background: brown;
color: white;
}
</style> In the second example I have written three component libraries in React. Most of this work has been getting the single element components right. I love Svelte because the reactive nature of components removes most of the performance code needed in React. Transitions in Svelte are so much easier too. I am doing all my side projects in Svelte. I'd love to move to Svelte for the next iteration of our companies UI library however the story around wrapping elements and keeping their API makes me hesitate. |
@Rich-Harris Congratulations on new job. Any thoughts on Is it feasible to make this perform as well as native Svelte elements both in terms of terse compiled output and runtime performance? |
See also #2226 |
Describe the problem
I might be missing something but it seems very difficult in Svelte to create components that do nothing more than style basic HTML elements. This makes creating component libraries hard because single element components (buttons, inputs, hr, etc) are the foundation layer of creating a component library. Let's say you want to create a component that does nothing but apply some styles to a button or input. Those styles might also be affected by props. At first it seems trivial:
The problem is the button can't be clicked ... easily fixed:
Actually there are a bunch of handlers our users might need. I hope I do not miss any and no new ones get added to the HTML spec:
Now we have added these handlers the compiled output to my component is massive. It shows I am creating a bunch of listeners that most of my consumers won't use so this is using up memory for each instance. So Svelte is no longer feeling very svelte:
Then we need things like ids and data attributes ... but then there is that warning in the docs that spreading props is not ideal and can't be optimized:
So now I have a deoptimized component and all the cool stuff in Svelte does not work on my Button
For inputs binding does not work if you do a props spread:
I just wanted to make the button brown when it was primary and I had to do a ton of boilerplate for every event an element might receive and I lost a lot of functionality (use, transition). It means creating a styled button is for advanced users not beginners. Styled buttons, links, inputs is the bread and butter of building websites and it feels hard to do this well in Svelte.
At the moment because single elements wrapped in components lose Svelte powers I find myself reapplying utility classes to basic elements rather than consolidating style logic into reusable atoms in a component library.
Describe the proposed solution
It would be great to have a special
thing
that was just for styled elements. I'd be happy if all it could do was modifystyle
andclass
props and perhaps enforce atype
forinput
. All other props, event handlers, actions, bindings get automatically forwarded to the element. I.e. it allows users to create things that have the same API as Svelte elements not Svelte components. Think of them as middleware or a proxy. They may need a different file extension or compiler options. They might look like this but I am open to other ways of achieving the same thing:It can then be used to apply styling logic to an element
Nice to have but not essential
An
as
prop:There might be an allow list and disallow list for element types.
Alternatives considered
In some cases allowing multiple supporting elements would be handy e.g. checkboxes are often wrapped in a label however once we allow multiple elements we do not know which element to send which forwarded which attributes to. Typically you would want values to go to the hidden input and animations and transitions to be forwarded to the container. So it seems best to limit this to single element components only.
Another alternative might be middleware components, they do not render anything but parents can manipulate the props, handlers and styles of their children until finally the props, handlers and styles reach a single element. So the source of an Input
elementComponent
might look like this:This requires two new kinds of components
elementComponents
andpropMiddleware
components.Importance
would make my life easier
The text was updated successfully, but these errors were encountered: