Add support for native form submissions #1240
Open
+39
−9
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Remaining issues
Read the proposal below first. This is so we don't miss things.
selectedInitially
andstate
names could be improvedpreset
array key should be supported.append()
to add the hidden inputs to the end of the element is causing issues withspace-y-
utilities as extra margin bottom is being addedThe scenario
At the moment, if a user tries to use Flux with native form submissions, such an in a Blade only app, some components won't submit as they are custom components.
Those components are:
The proposal
There are two PRs for this, one each for Flux and Flux Pro
Fixes #341
These PRs add support for native form submissions by rendering hidden inputs for components that don't have native support.
The
submittable
mixinTo get this to work, a
submittable
mixin has has been created.Submittable takes 3 pieces of information:
Internally there are 3 pieces of information:
Name
name
is pulled from thename
attribute on the component. If there is no name attribute, the hidden inputs will not render.Value
value
initially is thevalue
attribute pulled from the component and for some components this will be updated as theselectable
value changes, such as in radios and date pickers. Where as for checkboxes and switches, once this is set, it should not change. This is the value that will be output to the hidden input.State
state
is a boolean which determines whether the hidden inputs should be rendered or not. State is set by theselectedInitially
prop. Typically this tracks theselectable
value and is true/false depending on the contents of theselectable
value.The names
selectedInitially
andstate
were just copied fromselectable
. They don't seem to capture exactly what it is for, so these could be improved.The update process
Because of the different data types and checked/selected statuses, sometimes we need to update the value that
submittable
is tracking. We then need to update whether the hidden inputs should be rendered or not.That is why you will see two calls
.setValue()
and.update()
in most of the selection/ update hooks and others will just have.update()
..setValue()
updates the internal value of thesubmittable
that will be output to the hidden input..update()
determines whether the hidden inputs should be rendered on not, based on whether the data that has been passed in has a value or not. For example an empty array/ empty object will not render hidden inputs.Changes to
name
propSomething that needed to change was the mapping of the name prop for the Blade components. Previously the name prop was set to the value of
wire:model
, if there was one. This name attribute was never forwarded onto the components.But for native form submissions to work correctly, we first need to detect whether a
name
prop had been passed in. To do this, I've had to set thename
prop tonull
by default. This allows us to detect whethername
has been passed in or not by checking if it'snull
. We can now determine whethername
should be rendered on the component as an attribute or not.If it's
null
, we don't render thename
attribute and instead set it's value to the value of thewire:model
for error handling purposes only.Where as if
name
has a value, we shouldn't override it fromwire:model
and we also need to ensure it gets rendered as an attribute on the component.Calendar and date picker support for arrays from
old()
and manually passed valuesTo support passing values directly from Laravel's
old()
andrequest()
helpers directly into the calendar and date picker components, I've updated how thevalue
attribute gets processed.I've made
value
a prop now, so it can accept strings like is has to date, but it now also supports passing in arrays.For a range picker, it can accept an associative array with
start
andend
keys and this will be processed into thestart/end
string format. If one of start or end is missing, then it will just be an empty string.For a multiple picker, it can accept an array with date values, and this array will be imploded into a comma separated string, like
date1,date2,date3
.One issue
The only thing that is not supported is for the range picker, if a preset has been selected, then it will submit an array like the below (see the components section below for more details).
But currently there is no way to pass the preset key into the calendar or date picker components so the preset is selected again.
Should we add support for this?
Hidden inputs not durable
Currently hidden inputs are not durable if a Livewire request happens. So we need to find a way to include them. This is needed if someone is using Livewire for pieces of a native form submission, we don't want Livewire to wipe out any hidden inputs.
Append breaks because of
space-y-
We are appending the hidden elements to the end of the component's contents. This causes issues if the component is using
space-y-
like the checkbox group is, as it's causing margin bottom to appear on the element before the hidden inputs.Without anything selected

With something selected

Notice the space now below the SMS checkbox
Components
Below is a list of all the components with details on how to use them and what they will output.
Calendar/ date picker
The calendar and date picker both return the same data structures, so will be shown together using calendars as the example.
If you just have a calendar component and it has a name and a value, a hidden input will be rendered. If no value is provided initially, then the hidden input will only be rendered once something is selected. If the selection is removed, the hidden input is removed. This is different to how the native date input is handled which returns an empty string
""
by default.Returns: calendar="2025-03-19"
Returns: calendar="the-last-value"
If a calendar range picker is used and a range is selected, then it will return two pieces of data.
Returns:
This is translated by Laravel into a single array:
It's because of this, that the calendar and date picker components were updated to accept arrays being passed into the
:value
attribute, as theold()
andrequest()->input()
will both return an array.If presets are also used, then
preset
will be an additional key in the above array.If a calendar with multiple is used, then it will return a piece of data for each selected date.
Returns:
This is translated by Laravel into a single array:
Checkbox
If a checkbox has a name and a value, a hidden input will be rendered with both of those attributes as long as the checkbox is checked. If it is unchecked, the hidden input is removed. This is inline with the native checkbox which only sends a value if it's checked.
Returns: notifications="email"
If a checkbox only has a name and not a value, the value is set to
on
which is what the browser defaults to on the native checkbox if there is no value.Returns: notifications="on"
If a checkbox on page load has the checked attribute, or it's set to true, then the hidden input will be rendered.
Checkbox group
Checkbox groups support adding name attributes to the individual
checkbox
components, but the name needs to use the standard HTML name array syntaxnotifications[]
so it is grouped accordingly and the checkboxes don't overwrite each other when the form submits.But we also have support for just setting the name on the
checkbox.group
component, so it doesn't need to be set on everycheckbox
. In this scenario, the checkbox group already knows it's array based, so jus taddingnotifications
is enough, the array syntax isn't needed.Checkboxes can also be used on their own without the
checkbox.group
component and as long as they are using the HTML name array syntax, they will be grouped together.Editor
The editor component can work in a couple of ways.
The first is with shorthand syntax. A
value
attribute can be added to the editor component to pass initial data in.Returns: content="the last value"
But it can also be used long form, where the previous data is passed into the
editor.content
slot.Radio
Radio components cannot be used outside of a
radio.group
component, so it is required that thename
attribute goes on theradio.group
component.Returns: payment="ach"
This also works the same way for segmented and card variants.
Returns: role="editor"
Returns: shipping="standard"
Select
With all selects, the
name
attribute needs to go on theselect
component.If using a default select, if there are no values on the
select.option
components, then the value of the label will be returned.Returns: industry-default="Design services"
Where as if value attributes are added to each of the
select.option
components, then those values will be used.Returns: industry-values="photography"
If using the listbox variant, the principals are the same as above.
Returns: industry-listbox="Design services"
Returns: industry-listbox-values="photography"
If using the
multiple
option, there will be a hidden input created for each of the selected options using the array syntax.Returns:
Combobox
The combobox currently has issues, it should work like the other options. But for some reason, it won't load the
value
attribute and select the correct option and update the input with the selected value.But it submits happily, which is the main piece of this PR.
Returns: industry-combobox="Design services"
Using
value
onselect.option
also works happily (again won't load from value initially).Returns: industry-combobox-values="design-services"
Switch
The switch component just needs a name attribute. It will then return
"true"
if the switch has been selected and not return anything if it hasn't.Returns: enable-notifications="true"