Open theetrain opened 1 year ago
Also related:
I agree that we should only forward useful events.
A lot of components have a wrapping div
in which many events are forwarded to. We should not forward events in these cases as it generates a lot of boilerplate code. A user can always wrap the component with a div
and listen to events as they bubble up.
Furthermore, it can be confusing if we forward events to different elements.
Example:
<!-- events forwarded to the div are not useful and can be done by the consumer -->
<div
on:click
on:mouseover
on:mouseenter
on:mouseleave
>
<input on:input />
</div>
@metonym I added "Prop ordering" above.
On another note, I noticed <Button>
has a skeleton
prop whereas other components like <TextInput>
have a separate <TextInputSkeleton>
component. Should we prefer props or components? I'd say components are better for tree-shaking. The user experience comparison would be:
As props:
<form method="POST" action="?/deleteProfile" use:enhance>
<Button
type="submit"
kind="tertiary"
size="lg"
id="abc123"
skeleton={!ready}
/>
Delete Profile
</Button>
</form>
As components:
{#if ready}
<form method="POST" action="?/deleteProfile" use:enhance>
<Button
type="submit"
kind="tertiary"
size="lg"
id="abc123"
/>
Delete Profile
</Button>
</form>
{:else}
<ButtonSkeleton size="lg" />
{/if}
@theetrain agree - skeleton variants should live as standalone components. We should remove the skeleton prop.
Do we want to allow $$restProps
for single-element components such as Button
and Layer
? Strictly speaking, it isn't a performance concern any more than attributes
or buttonAttributes
would be, and would allow for a less-cluttered API where possible.
Example with $$restProps
:
<Button
kind="secondary"
type="submit"
data-test-id="abc123"
>
Save
</button>
Example without $$restProps
:
<Button
kind="secondary"
type="submit"
attributes={{ 'data-test-id': "abc123" }}
>
Save
</button>
One other trade-off when using $$restProps
is not having Carbon-specific props appear at the top of the autocomplete list; since it would alphabetize props and element attributes in one giant list.
Related comments: https://github.com/carbon-design-system/carbon-components-svelte/pull/1895#discussion_r1458187996, https://github.com/carbon-design-system/carbon-components-svelte/pull/1932#discussion_r1518998468
cc @metonym @brunnerh @SimpleProgrammingAU
My personal preference is for a uniform API. I like the idea of being able to use CDS Svelte and know I should never use $$restProps
without exception.
I like the idea of being able to use CDS Svelte and know I should never use
$$restProps
without exception.
It just shifts things, instead you now need to know which attribute object is the relevant one if any (because the delineation of special properties and plain attributes is not entirely clear - see https://github.com/carbon-design-system/carbon-components-svelte/pull/1895#discussion_r1458187996). These properties are meant to standardize, but this is just not possible to the degree envisioned.
The syntax is also just plain worse, it is more verbose, noisy and forces a switch away from HTML to JS in the markup, even for static attributes. This goes against Svelte's core HTML-first approach.
I would argue for the continued use of $$restProps
where there is a logical candidate for receiving them. E.g. for any form elements the primary interactive element (e.g. TextInput
-> <input>
, Select
-> <select>
, Button
-> <a>
/<button>
).
Other elements that are important, like the root element for layout, a <label>
or icon could have these additional attribute properties which hopefully should rarely need to be accessed at all.
In Svelte 5 rest props will further be strengthened with the ability to forward all event handlers. The feature was always meant to support the wrapping of elements in generic components, it does not make sense to me to ditch it.
@brunnerh if I were to formalize your note into a protocol, it could be:
$$restProps
on that element, and add attribute props for other elements when requested or where it makes the most sense (such as label
).$$restProps
to the outer-most wrapping element, if any; and provide individual attribute props for all interactive child elements).Mind you, some extra considerations may need to be made for #1622 (thinking about use:
and adapting links, buttons, and form) and Svelte 5, but I think the above protocol sounds agreeable. Perhaps slots and snippets could reduce the need for attribute props even further.
Note: "attribute props" == "pass-through props"
Personally, I echo @SimpleProgrammingAU's sentiment.
$$restProps
is discouraged because it's difficult to statically analyze/optimize.$$restProps
forwarded to the "top-level" element or the "most important" element (e.g., an input or button)? Additionally, a prop named inputProps
is very semantic.$$restProps
, this would inevitably lead to creating object props anyways, (e.g., menuProps
etc..).
$$restProps
is discouraged because it's difficult to statically analyze/optimize.
The same should be true for spreading any object as props. For component libraries there is no way around this.
Predictable API: is
$$restProps
forwarded to the "top-level" element or the "most important" element (e.g., an input or button)? Additionally, a prop namedinputProps
is very semantic.
It's not predictable because some props (e.g. disabled
in Button
as referenced) need special handling or are not simple attributes to be passed on to one element, so you might expect them on a *Props
object but things will not behave as expected if you set them there.
Multiple spreading: what if I want to spread arbitrary props to multiple elements? Even if using
$$restProps
, this would inevitably lead to creating object props anyways, (e.g.,menuProps
etc..).
True, but ideally the secondary elements would not need as much customization.
Status: 🟡 Proposal
We have several props and dispatched event names that are reused across components. Let's improve their consistency in naming and intent.
Todo
titleText
tolabelText
Prop ordering
Rather than alphabetical order, props SHOULD be ordered in a manner that is intuitive and useful to users. Sveld will generate documentation in the order props are defined within components.
Proposed ordering:
ref
or[elementName]Ref
propskind
size
labelText
andhideLabel
$$restProps
below)Prop names
Props that have different intent follow different aspirational rules.
The following MUST be followed:
kind
to represent a set of other named options for visual or interactive component representationsskeleton
variants should be separate components; and not a prop toggleThe following SHOULD be followed:
true
orfalse
values are represented as plain adjectives without anis
prefix. Examples:expandable
,selectable
,selected
. Prefer to have them default tofalse
for easy truthy flagging. i.e. absense ofselectable
impliesselectable == false
, but the presence ofselected
toggles totrue
.disabled
for<Button>
aria-label
for<TextInput>
ref
prop with 2-way binding should be provided to allow focusing via JS. Appropriate elements include, but aren't limited to:size
should have all possible values explicitly typed, including defaults, such as'sm' | 'md' | 'lg'
instead of'sm' | 'lg'
. Components impacted:Form components
Components that render form inputs MUST have the following props:
labelText
for the labelhelperText
for any helpful or hint text placementname
,id
,value
,checked
readonly
should bereadOnly
Prop behaviours SHOULD include:
value
is bindable, and can be instantiated (currently not the case for Combobox)Events
Demo: https://svelte.dev/repl/9b1e3a7822bb4aac9418c95f518523e7?version=3.55.1
In general:
pointer
events overmouse
events to ensure cross-compatibility with touch and desktop devices. Usemouse
ortouch
only when necessaryDispatched events
Forwarded events
on:input
,on:submit
, andon:change
; this includes TextInput, ComboBox, and others$$restProps
See https://github.com/carbon-design-system/carbon-components-svelte/issues/1064#issuecomment-1375954124
$$restProps
since it's a discouraged feature of SveltebuttonAttributes
for<Button>
; andlabelAttributes
andinputAttributes
for<TextInput>
Slots