diff --git a/.changeset/brown-wasps-exercise.md b/.changeset/brown-wasps-exercise.md new file mode 100644 index 0000000000..2a50635cc5 --- /dev/null +++ b/.changeset/brown-wasps-exercise.md @@ -0,0 +1,5 @@ +--- +"@primer/view-components": patch +--- + +Fix generated field ids to remove brackets diff --git a/app/lib/primer/forms/check_box.rb b/app/lib/primer/forms/check_box.rb index cd6a6d17d0..f9f37abe2e 100644 --- a/app/lib/primer/forms/check_box.rb +++ b/app/lib/primer/forms/check_box.rb @@ -11,6 +11,13 @@ def initialize(input:) @input.add_label_classes("FormControl-label") @input.add_input_classes("FormControl-checkbox") + # Generate custom ID that preserves brackets from the name + unless @input.input_arguments[:id].present? + generate_custom_id + # Update the label's for attribute to match the new ID + @input.label_arguments[:for] = @input.input_arguments[:id] + end + return unless @input.scheme == :array @input.input_arguments[:multiple] = true @@ -32,6 +39,27 @@ def nested_form_arguments private + def generate_custom_id + # Generate an ID from the name that preserves special characters like brackets + # For array scheme: name + "_" + value (e.g., "permissions[3]_foo") + # For boolean scheme: just the name (e.g., "long_o") + base_name = @input.name.to_s + + # For array scheme, Rails appends [] to the name, so we remove it for ID generation + # but only the trailing [] that Rails adds, not brackets that are part of the original name + # Regex /\[\]$/ matches literal "[]" at the end of the string + base_name = base_name.sub(/\[\]$/, "") + + # For array scheme, append the value to make IDs unique + # For boolean scheme, just use the base name + # Note: Rails automatically escapes HTML attributes, so special characters are safe + if @input.scheme == :array && @input.value.present? + @input.input_arguments[:id] = "#{base_name}_#{@input.value}" + else + @input.input_arguments[:id] = base_name + end + end + def checked_value @input.value || "1" end diff --git a/test/lib/primer/forms/checkbox_input_test.rb b/test/lib/primer/forms/checkbox_input_test.rb index 6d55cbd5ee..395e842798 100644 --- a/test/lib/primer/forms/checkbox_input_test.rb +++ b/test/lib/primer/forms/checkbox_input_test.rb @@ -61,4 +61,40 @@ def test_nested_form_can_be_hidden_independently assert_selector "input[name=foo]" assert_selector "input[name=bar]", visible: :hidden end + + def test_preserves_brackets_in_generated_ids + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |check_form| + check_form.check_box( + name: "permissions[3]", + label: "Foo", + value: "bar", + scheme: :array + ) + end + end + end + + # The ID should preserve brackets from the name + assert_selector "input[id='permissions[3]_bar']" + assert_selector "label[for='permissions[3]_bar']" + end + + def test_preserves_brackets_in_generated_ids_with_boolean_scheme + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |check_form| + check_form.check_box( + name: "user[settings][email]", + label: "Email notifications" + ) + end + end + end + + # For boolean scheme, the ID should just be the name with brackets preserved + assert_selector "input[id='user[settings][email]']" + assert_selector "label[for='user[settings][email]']" + end end