Skip to content

Commit 4e702c8

Browse files
Copilotjonrohan
andauthored
Fix checkbox ID generation to preserve brackets in field names (#3878)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jonrohan <54012+jonrohan@users.noreply.github.com> Co-authored-by: Jon Rohan <rohan@github.com>
1 parent a0d5227 commit 4e702c8

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

.changeset/brown-wasps-exercise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/view-components": patch
3+
---
4+
5+
Fix generated field ids to remove brackets

app/lib/primer/forms/check_box.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ def initialize(input:)
1111
@input.add_label_classes("FormControl-label")
1212
@input.add_input_classes("FormControl-checkbox")
1313

14+
# Generate custom ID that preserves brackets from the name
15+
unless @input.input_arguments[:id].present?
16+
generate_custom_id
17+
# Update the label's for attribute to match the new ID
18+
@input.label_arguments[:for] = @input.input_arguments[:id]
19+
end
20+
1421
return unless @input.scheme == :array
1522

1623
@input.input_arguments[:multiple] = true
@@ -32,6 +39,27 @@ def nested_form_arguments
3239

3340
private
3441

42+
def generate_custom_id
43+
# Generate an ID from the name that preserves special characters like brackets
44+
# For array scheme: name + "_" + value (e.g., "permissions[3]_foo")
45+
# For boolean scheme: just the name (e.g., "long_o")
46+
base_name = @input.name.to_s
47+
48+
# For array scheme, Rails appends [] to the name, so we remove it for ID generation
49+
# but only the trailing [] that Rails adds, not brackets that are part of the original name
50+
# Regex /\[\]$/ matches literal "[]" at the end of the string
51+
base_name = base_name.sub(/\[\]$/, "")
52+
53+
# For array scheme, append the value to make IDs unique
54+
# For boolean scheme, just use the base name
55+
# Note: Rails automatically escapes HTML attributes, so special characters are safe
56+
if @input.scheme == :array && @input.value.present?
57+
@input.input_arguments[:id] = "#{base_name}_#{@input.value}"
58+
else
59+
@input.input_arguments[:id] = base_name
60+
end
61+
end
62+
3563
def checked_value
3664
@input.value || "1"
3765
end

test/lib/primer/forms/checkbox_input_test.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,40 @@ def test_nested_form_can_be_hidden_independently
6161
assert_selector "input[name=foo]"
6262
assert_selector "input[name=bar]", visible: :hidden
6363
end
64+
65+
def test_preserves_brackets_in_generated_ids
66+
render_in_view_context do
67+
primer_form_with(url: "/foo") do |f|
68+
render_inline_form(f) do |check_form|
69+
check_form.check_box(
70+
name: "permissions[3]",
71+
label: "Foo",
72+
value: "bar",
73+
scheme: :array
74+
)
75+
end
76+
end
77+
end
78+
79+
# The ID should preserve brackets from the name
80+
assert_selector "input[id='permissions[3]_bar']"
81+
assert_selector "label[for='permissions[3]_bar']"
82+
end
83+
84+
def test_preserves_brackets_in_generated_ids_with_boolean_scheme
85+
render_in_view_context do
86+
primer_form_with(url: "/foo") do |f|
87+
render_inline_form(f) do |check_form|
88+
check_form.check_box(
89+
name: "user[settings][email]",
90+
label: "Email notifications"
91+
)
92+
end
93+
end
94+
end
95+
96+
# For boolean scheme, the ID should just be the name with brackets preserved
97+
assert_selector "input[id='user[settings][email]']"
98+
assert_selector "label[for='user[settings][email]']"
99+
end
64100
end

0 commit comments

Comments
 (0)