Replies: 2 comments
-
I think we should extrapolate the important parts into a Rationale section on the rich select docs. I am also fine with just saving this original file as a design document or something but put it elsewhere, maybe in our own docs repo or something. I think for our users it could be confusing to run into out of date design docs. |
Beta Was this translation helpful? Give feedback.
-
Hi, We are closing this issue because we're changing the way we handle feature requests. Your issue will get the "votes needed" label, and people can add 👍 reactions to vote and show interest. It will be reopened when this feature gets picked up. This we way we clearly focus on bugs in our open issues. At the same time we can see what community interest there is for new features. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Design considerations for new Custom Fields (draft)
Whenever a new type of Form component is made, a list of questions needs to be addressed:
This document is meant to illustrate how all of the above mentioned factors are taken
into account and prioritized.
It does so by going through the design process of the concept 'listbox',
step by step.
The listbox concept will end up in several web components:
listbox with collapsible dropdown
The need for a listbox
The reason we need a non platform, custom built version of a listbox component,
is very well explained on MDN:
On top of this, a listbox allows us to create advanced user experiences:
Creating a Form Control
The goal of every form web component we build is to end up as a FormControl.
More specific: either as a Field or a Fieldset.
In short, a FormControl provides a normalized api, a modelValue, validation, formatting,
interaction states, an accessible html structure for labels, feedback, help texts and addons.
Please see the Custom Fields tutorial
to get an idea of how to build a custom FormControl (a range slider in this particular case).
A FormControl is meant to be the single point of interaction for Application Developers.
All relevant form data are specified on this layer by him/her.
Everything that is specified within a field(being slotted content), has a presentational
purpose only.
Getting the right api: accessibility
As far as the api is concerned, the ideal api for our rich select would be:
The difference with our api is the lack of a
<lion-listbox>
around<lion-option>
sIn order to transform the ideal api into an accessible solution, it needs to be transformed into
something like this:
The element with [role=listbox] and [aria-activedescendant] needs to be in the same dom as the
elements with [role=option].
Attempting to provide the ‘ideal api’ as suggested above poses a challenge:
since we would have two different doms (shadow and light), the aforementioned elements would not
find each other(1).
A slight alteration of the api (moving [role=listbox] element to the light dom as well) solves
this problem:
The api is conceptually identical to that of the already existing native select:
Getting the right api: presentational content
Let’s first revisit our main Fields:
lion-input
,lion-textarea
,lion-select
,lion-radio
andlion-checkbox
.For the sake of clarity and to get a good grasp of conceptual differences between different layers in
our system, the names of our LionField extensions will be changed to these within this document:
The field-text, field-textarea and field-radio/field-checkbox have an api roughly resembling this:
Whenever a presentational component used within those fields needs to be changed, content
projection is the right approach for this. In the example below, the label can’t be provided as a
String:
Similarly, the Field for native select provides a
[slot=input]
for presentational purposes.The selected option is reflected in the
.modelValue
.The presentational part(2), the options, should be defined by the Application Developer.
Notice that contrary to the example above, an Application Developer has two places to get/set
his/her value:
Using [slot=input] directly is not recommended and should be considered an anti
pattern: it doesn't have the normalized Field api and it creates an unpredictable data flow/DX
on top of this.
Again, [slot=input] should be considered as being presentational only...
Summarized: what all of the different field types above have in common is this api for the
Application Developer:
All the relevant interaction with regard to form state happens (and should happen) on the Field layer.
Field or Fieldset?
For most FormControls, the answer to this question is really simple: a LionField wraps just one
input, a LionFieldset wraps many.
A listbox can semantically be seen as a select. A select on its turn can be seen as
a radiogroup and a select with option [multiple] can be seen as a checkbox group.
Although both of these currently are wrapped in LionFieldset, the fieldset contains to much
unnecessary code for the
lion-listbox
, so only the same mixins the LionFieldset consists ofare used.
Options have a lot in common with radio inputs and checkboxes (multiselect). There main difference
seems to be [aria-selected] for option (having possible values of true and false) and
[aria-checked] for radio buttons and checkboxes (having a tristate, including indeterminate).
Another difference is the fact that input[type="radio/checkbox"] can be used on its own, whereas
an option can't.
So, we would end up with (3):
Subclassers api enhancements
Keep in mind all Lion components are flexible layers, allowing the Application Developer to fully
control the presentational part.
A subclasser might alter the api by do something like this for a listbox Field:
Or, for a combobox Field:
Under the hood it uses a cloneable node as option template and generates the "input"/"list" slot.
How the provided data in
.options
and the generated<my-option>
elements work together,should be specified on this level.
See https://vaadin.com/components/vaadin-select/html-examples for a comparable api.
Not perfect (yet...)
Since our current namings can lead to questions, I would opt for a rename to:
Would avoid mistakes and confusion for Application Developers. However, input (or
interactive element)
would make more sense for Subclassers.
More public/api changes for forms in general:
[aria-required=true] to [slot=input]
Most of these are breaking and should be done in our next milestone.
Summarized
Summarized, most of the api choices are a compromise of:
Transferring the
lion-option
s to a part of the light dom that already has the listbox, would bea technically possible, but hacky solution.
Putting [role="listbox"] on the host(like suggested before) is not a solution either: it causes the button to be a child of the listbox and this would confuse
screen reader users.
The part here that could be considered non presentational here is the "value" provided to option. It kind of reflects ‘potential form state’. In this api we’ve chosen alignment with the platform, but
One could argue that ‘the lack of selection’ is also part of form state, and should be covered in the modelValue.
Something worth discussing. We currently apply this to the ChoiceGroups (radioGroup, checkboxGroup),
Although my personal opinion, in retrospect is that it complicates DX and something like Vue(appreciated for its DX in general) does might be easier: https://vuejs.org/v2/guide/forms.html
What could be open for discussion is whether we can’t just say 'field-select .modelValue=${myArray}'.
The main reason not to do this, is because you would end up with a situation where you would have an intermangling
Between form state (this is what the .modelValue is supposed to be about) and presentation (you could end up with logic about
whether an icon needs to be displayed or not inside your modelValue)
An alternative can possibly be accomplished by creating some kind of DSL like the vaadin-grid does for instance: https://vaadin.com/components/vaadin-grid/html-examples
But, it has the same drawbacks as pointed out already
Groups
Does all the bookkeeping for child form controls and stores those in
.formElements
.(groups wrapping choice elements like radio, checkbox, option that extend ChoiceInputMixin).
RadioGroup
CheckboxGroup
Listbox
Select
(-rich)Combobox
There are two modes:
Fieldset mode
In this case,
.formElements
behaves like an object.In the fieldset mode, many 'regular' child input elements will be wrapped, like:
x
andz
will be available under.modelValue.x
and.modelValue.y
.Choice Group mode
In this case,
.formElements
behaves like an array.(currently, CheckboxGroup and RadioGroup still require
.formElements['name[]']
notation,but this will be corrected in a future breaking release).
Note: code below is pseudo code and doesn't reflect real elements.
Children will be available under
.modelValue[0]
and.modelValue[1]
.Sub modes
single select
In this case there is a property
.checkedValue
which will be the modelValue of the selected.multi select
In this case there is a property
.checkedValues
which will be an array of selectedmodelValues.
Beta Was this translation helpful? Give feedback.
All reactions