heartcombo / simple_form

Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
http://blog.plataformatec.com.br/tag/simple_form
MIT License
8.22k stars 1.32k forks source link

Radio button set to readonly (invalid HTML5) #1730

Closed KevinBongart closed 2 years ago

KevinBongart commented 3 years ago

Current behavior

I have this wrapper in my app, coming from this repo:

config.wrappers :vertical_collection, item_wrapper_class: 'form-check', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
  b.use :html5
  b.optional :readonly
  b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
    ba.use :label_text
  end
  b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
  b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
  b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
end

…

config.wrapper_mappings = {
  …
  radio_buttons: :vertical_collection,
  …
}

I'm not entirely sure how simple_form uses the readonly option, but I recently ran into an issue (on Stack Overflow) where Capybara couldn't interact with one of the two radio buttons without a JavaScript driver (such as selenium_chrome_headless). It looks that is because the resulting HTML has a readonly="readonly" on one of the two radio buttons, which apparently is not valid HTML.

Here's the ERB code:

<%= simple_form_for(@foo) do |f| %>
  <%= f.simple_fields_for :bar do |b| %>
    <%= p.input :baz, as: :radio_buttons, label: '' %>
  <% end %>

  <%= f.button :submit %>
<% end %>

The baz field is a boolean attribute on the bar class, and the line generates this HTML (note the readonly on the second input):

<fieldset class="form-group radio_buttons optional foo_bar_baz form-group-valid">
  <legend class="col-form-label pt-0"></legend>
  <input type="hidden" name="foo[bar_attributes][baz]" value="">

  <div class="form-check">
    <input class="form-check-input is-valid radio_buttons optional" type="radio" value="true" checked="checked" name="foo[bar_attributes][baz]" id="foo_bar_attributes_baz_true">
    <label class="collection_radio_buttons" for="foo_bar_attributes_baz_true">Yes</label>
  </div>

  <div class="form-check">
    <input class="form-check-input is-valid radio_buttons optional" readonly="readonly" type="radio" value="false" name="foo[bar_attributes][baz]" id="foo_bar_attributes_baz_false">
    <label class="collection_radio_buttons" for="foo_bar_attributes_baz_false">No</label>
  </div>
</fieldset>

Capybara has since then been fixed to ignore the readonly attributes on radio buttons, but I'm still wondering about where in the stack the issue originates, if that's an issue at all, and what I can do to work around it.

Environment

Expected behavior

I believe there shouldn't be a readonly="readonly" attribute on the radio button unless explicitly passed in, and even then, since it's apparently not valid HTML, maybe some validation should prevent it. If you believe otherwise, I'd love to hear the rational behind it and figure out a workaround.

nashby commented 2 years ago

Hey @KevinBongart. You can find more info about this issue here https://github.com/heartcombo/simple_form/issues/1257. It's not really optimal but that's how it works at the moment.

TL;DR Just remove b.optional :readonly from your configuration and use readonly component when you need