Repository: primer/view_components (Ruby)

Issue:
FormGroup does not honor system arguments
Ahoi!

When composing a primer form with the DSL, one has the possibilities to group some inputs into form groups. This has the very famous use case of grouping some inputs horizontally, while the whole form stacks vertically.

Code example:

```ruby
form do |new_item_form|
  new_item_form.group(layout: :horizontal) do |input_group|
    input_group.text_field(
      name: :label,
      label: "Label",
      visually_hide_label: true,
      required: true,
      placeholder: "Item label"
    )
    input_group.text_field(
      name: :short,
      label: "Short",
      visually_hide_label: true,
      full_width: false,
      required: false,
      placeholder: "Short label"
    )
  end

  new_item_form.group(layout: :horizontal) do |button_group|
    button_group.button(name: :cancel, label: "Cancel", scheme: :default)
    button_group.submit(name: :submit, label: "Save", scheme: :primary)
  end
end
```

The text fields together stretch to full width, but my intend with the button group is, that they are right aligned. When inspecting the DOM in the browser, the solution is almost trivial.

As the form is wrapped in a `FormControl-spacingWrapper`, which is `display:flex`, and each `form.group(layout: :horizontal)` creates a child `<div class="FormControl-horizontalGroup"></div>`. So, one could add `align-self: end` to the div of the form group and everything looks as intended.

The primer way of doing so is passing system arguments. But, alas, amending the form group in a way to have 

```ruby
new_item_form.group(layout: :horizontal, align_self: :end)
```

has no effect. [Looking into the code](https://github.com/primer/view_components/blob/main/app/lib/primer/forms/group.html.erb), it seems, that on the group no system arguments are passed down to the created `div`. From the code I'd like to raise two questions:

1. Is it possible to enable the system arguments on the created element of the group?
2. Why actually is there a conditional element creation? Why is a vertical form group not honored with a container for itself? Then it could receive system arguments, too, being able to change alignment or spacing of certain form groups directly from the form definition.

Looking forward for your answers!

Best regards!


Discussion:
Thanks for writing in! @camertron given your context on forms, could you take a look at answering the two questions above? 🙏🏻 
Hey @Kharonus! Thanks for filing such a detailed and reproducible issue 😄 I believe the decision to not support system arguments on groups was because groups were really only designed to support vertical/horizontal orientations as you noted. I was initially hesitant to allow arbitrary system arguments on groups because the forms framework generally tries to expose as few layout/styling options as possible to curtail potential accessibility issues, etc. However, I've revised my opinion a bit based on your description of the problem. Since we support system arguments on most other parts of the framework, it seems reasonable to support them in groups as well.

See: https://github.com/primer/view_components/pull/3149
Great, those are very good news. Thanks a ton for the quick PR!



Patch:
diff --git a/.changeset/hip-deers-rhyme.md b/.changeset/hip-deers-rhyme.md
new file mode 100644
index 0000000000..58401478a6
--- /dev/null
+++ b/.changeset/hip-deers-rhyme.md
@@ -0,0 +1,5 @@
+---
+'@primer/view-components': minor
+---
+
+Allow form groups to accept system arguments
diff --git a/app/lib/primer/forms/base_component.rb b/app/lib/primer/forms/base_component.rb
index 428f4f72d4..0199afc8b1 100644
--- a/app/lib/primer/forms/base_component.rb
+++ b/app/lib/primer/forms/base_component.rb
@@ -61,14 +61,6 @@ def compile_and_render_template
         self.class.compile! unless self.class.instance_methods(false).include?(:render_template)
         render_template
       end
-
-      def content_tag_if(condition, tag, **kwargs, &block)
-        if condition
-          content_tag(tag, **kwargs, &block)
-        else
-          capture(&block)
-        end
-      end
     end
   end
 end
diff --git a/app/lib/primer/forms/group.html.erb b/app/lib/primer/forms/group.html.erb
index d918111edc..58058165ad 100644
--- a/app/lib/primer/forms/group.html.erb
+++ b/app/lib/primer/forms/group.html.erb
@@ -1,4 +1,4 @@
-<%= content_tag_if(horizontal?, :div, class: "FormControl-horizontalGroup") do %>
+<%= render(Primer::Box.new(**@system_arguments)) do %>
   <% @inputs.each do |input| %>
     <%= render(input.to_component) %>
   <% end %>
diff --git a/app/lib/primer/forms/group.rb b/app/lib/primer/forms/group.rb
index 889603470b..2b7239b7f8 100644
--- a/app/lib/primer/forms/group.rb
+++ b/app/lib/primer/forms/group.rb
@@ -17,6 +17,11 @@ def initialize(inputs:, builder:, form:, layout: DEFAULT_LAYOUT, **system_argume
         @form = form
         @layout = layout
         @system_arguments = system_arguments
+
+        @system_arguments[:classes] = class_names(
+          @system_arguments.delete(:classes),
+          "FormControl-horizontalGroup" => horizontal?
+        )
       end
 
       def horizontal?


Test patch:
diff --git a/test/lib/primer/forms/group_input_test.rb b/test/lib/primer/forms/group_input_test.rb
new file mode 100644
index 0000000000..623aee11f5
--- /dev/null
+++ b/test/lib/primer/forms/group_input_test.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "lib/test_helper"
+
+class Primer::Forms::GroupInputTest < Minitest::Test
+  include Primer::ComponentTestHelpers
+
+  def test_group_accepts_system_arguments
+    render_in_view_context do
+      primer_form_with(url: "/foo") do |f|
+        render_inline_form(f) do |sys_args_form|
+          sys_args_form.group(layout: :horizontal, border: true, p: 1) do |group|
+            group.text_field(name: :first_name, label: "First name")
+            group.text_field(name: :last_name, label: "Last name")
+          end
+        end
+      end
+    end
+
+    assert_selector ".FormControl-horizontalGroup.border.p-1"
+  end
+end
diff --git a/test/lib/primer/forms_test.rb b/test/lib/primer/forms_test.rb
index d6f7ef111b..d024523dad 100644
--- a/test/lib/primer/forms_test.rb
+++ b/test/lib/primer/forms_test.rb
@@ -297,12 +297,6 @@ def test_text_field_custom_element_is_form_control
     assert_selector "primer-text-field.FormControl"
   end
 
-  def test_siblings_are_form_controls_when_including_a_multi_input
-    render_preview :multi_input_form
-
-    assert_selector ".FormControl-radio-group-wrap + .FormControl"
-  end
-
   def test_toggle_switch_button_labelled_by_label
     render_preview(:example_toggle_switch_form)