diff --git a/CHANGELOG.md b/CHANGELOG.md
index cadc7cdc..e69223a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
- Fix `show_label='visually-hidden'` being ignored by `bootstrap_field`, `bootstrap_form` and `bootstrap_formset`, which rendered an ordinary visible label instead of one hidden from sight (#526). The string is truthy, so the check that adds the `visually-hidden` class only ever caught `False`, even though both values have always been documented as equivalent.
- Add `show_label` to `bootstrap_label`, accepting the same values as on `bootstrap_field`: `True`, `False`/`'visually-hidden'` to hide the label from sight but keep it for screen readers, and `'skip'` to render nothing (#526). A hidden label gets `visually-hidden` in place of the default `form-label`, as `bootstrap_field` and Bootstrap's own examples do; a `label_class` you pass yourself is kept either way.
+- Add a `wrapper` argument to `bootstrap_field`, `bootstrap_form` and `bootstrap_formset` (#438). With `wrapper=False` a field renders its label, widget, errors and help text without the wrapper `div`, so several fields can share one element of your own, such as an `input-group`. The classes the wrapper carried (`wrapper_class`, the horizontal `row`, and the required and validation indicator classes) are then not rendered, as there is no element to carry them; the `is-valid`/`is-invalid` classes on the widget are unaffected. `wrapper_class=""` keeps rendering `
` as before.
## 26.4 (2026-10-11)
diff --git a/docs/forms.rst b/docs/forms.rst
index 0fa47795..99bd2db5 100644
--- a/docs/forms.rst
+++ b/docs/forms.rst
@@ -50,6 +50,53 @@ Bootstrap 5 offers Input groups to combine fields and add-ons (both before and a
Note: input-group needs has-validation
https://github.com/twbs/bootstrap/blob/6b3254536bac263c39e3a536c3c13945210d91b2/site/content/docs/5.0/migration.md
+To put more than one field in a single input group, render the fields without their wrappers by
+passing ``wrapper=False``. Bootstrap lays out every child of an input group as a flex item, so a
+field's own label would be stretched into the row instead of sitting above it.
+
+Each input still needs an accessible name. A single ``
"
),
)
+
+
+class InputGroupTestForm(forms.Form):
+ first = forms.CharField(help_text="First help")
+ second = forms.CharField(required=False)
+
+
+class BootstrapFieldWrapperTestCase(BootstrapTestCase):
+ """Test the `wrapper` parameter of `bootstrap_field`."""
+
+ def test_wrapper_default_is_unchanged(self):
+ """Test that not passing `wrapper` renders the wrapper as before."""
+ self.assertHTMLEqual(
+ self.render("{% bootstrap_field form.test %}", context={"form": CharFieldTestForm()}),
+ (
+ '
'
+ 'Test'
+ ''
+ "
"
+ ),
+ )
+
+ def test_wrapper_false(self):
+ """Test that `wrapper=False` renders label and field without a wrapper."""
+ self.assertHTMLEqual(
+ self.render("{% bootstrap_field form.test wrapper=False %}", context={"form": CharFieldTestForm()}),
+ (
+ 'Test'
+ ''
+ ),
+ )
+
+ def test_wrapper_false_in_input_group(self):
+ """Test that two fields without wrappers can share one input group."""
+ self.assertHTMLEqual(
+ self.render(
+ '