]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Rewrite input group component (#25020)
authorMark Otto <markd.otto@gmail.com>
Fri, 22 Dec 2017 23:29:49 +0000 (15:29 -0800)
committerGitHub <noreply@github.com>
Fri, 22 Dec 2017 23:29:49 +0000 (15:29 -0800)
* Rewrite input group component

* Set the feedback to 100% width for input group

* Move from .row to .form-row for tighter layout

* no need for custom feedback here, we're using browser messaging

* add input group to validation examples

* add note about validating multiple

* migration note added

docs/4.0/components/button-group.md
docs/4.0/components/forms.md
docs/4.0/components/input-group.md
docs/4.0/components/navbar.md
docs/4.0/migration.md
scss/_input-group.scss
scss/mixins/_forms.scss

index 8fea3de901d977b84fb612703598695627abe43c..f08d2e3ecd260ea98c4699d675bebdc404b3187e 100644 (file)
@@ -60,7 +60,9 @@ Feel free to mix input groups with button groups in your toolbars. Similar to th
     <button type="button" class="btn btn-secondary">4</button>
   </div>
   <div class="input-group">
-    <span class="input-group-addon" id="btnGroupAddon">@</span>
+    <div class="input-group-prepend">
+      <div class="input-group-text" id="btnGroupAddon">@</div>
+    </div>
     <input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
   </div>
 </div>
@@ -73,7 +75,9 @@ Feel free to mix input groups with button groups in your toolbars. Similar to th
     <button type="button" class="btn btn-secondary">4</button>
   </div>
   <div class="input-group">
-    <span class="input-group-addon" id="btnGroupAddon2">@</span>
+    <div class="input-group-prepend">
+      <div class="input-group-text" id="btnGroupAddon2">@</div>
+    </div>
     <input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon2">
   </div>
 </div>
index 634b3288c586f1e0f87be03443d9975af2011670..d485ef4cddf2ff0f3d926d009bc2f67ff1f53b84 100644 (file)
@@ -482,7 +482,9 @@ The example below uses a flexbox utility to vertically center the contents and c
     <div class="col-auto">
       <label class="sr-only" for="inlineFormInputGroup">Username</label>
       <div class="input-group mb-2">
-        <div class="input-group-addon">@</div>
+        <div class="input-group-prepend">
+          <div class="input-group-text">@</div>
+        </div>
         <input type="text" class="form-control" id="inlineFormInputGroup" placeholder="Username">
       </div>
     </div>
@@ -512,7 +514,9 @@ You can then remix that once again with size-specific column classes.
     <div class="col-sm-3">
       <label class="sr-only" for="inlineFormInputGroupUsername">Username</label>
       <div class="input-group mb-2 mb-sm-0">
-        <div class="input-group-addon">@</div>
+        <div class="input-group-prepend">
+          <div class="input-group-text">@</div>
+        </div>
         <input type="text" class="form-control" id="inlineFormInputGroupUsername" placeholder="Username">
       </div>
     </div>
@@ -575,7 +579,9 @@ You may need to manually address the width and alignment of individual form cont
 
   <label class="sr-only" for="inlineFormInputGroupUsername2">Username</label>
   <div class="input-group mb-2 mr-sm-2">
-    <div class="input-group-addon">@</div>
+    <div class="input-group-prepend">
+      <div class="input-group-text">@</div>
+    </div>
     <input type="text" class="form-control" id="inlineFormInputGroupUsername2" placeholder="Username">
   </div>
 
@@ -725,17 +731,29 @@ When attempting to submit, you'll see the `:invalid` and `:valid` styles applied
 
 {% example html %}
 <form id="needs-validation" novalidate>
-  <div class="row">
-    <div class="col-md-6 mb-3">
+  <div class="form-row">
+    <div class="col-md-4 mb-3">
       <label for="validationCustom01">First name</label>
       <input type="text" class="form-control" id="validationCustom01" placeholder="First name" value="Mark" required>
     </div>
-    <div class="col-md-6 mb-3">
+    <div class="col-md-4 mb-3">
       <label for="validationCustom02">Last name</label>
       <input type="text" class="form-control" id="validationCustom02" placeholder="Last name" value="Otto" required>
     </div>
+    <div class="col-md-4 mb-3">
+      <label for="validationCustomUsername">Username</label>
+      <div class="input-group">
+        <div class="input-group-prepend">
+          <span class="input-group-text" id="inputGroupPrepend">@</span>
+        </div>
+        <input type="text" class="form-control" id="validationCustomUsername" placeholder="Username" aria-describedby="inputGroupPrepend" required>
+        <div class="invalid-feedback">
+          Please choose a username.
+        </div>
+      </div>
+    </div>
   </div>
-  <div class="row">
+  <div class="form-row">
     <div class="col-md-6 mb-3">
       <label for="validationCustom03">City</label>
       <input type="text" class="form-control" id="validationCustom03" placeholder="City" required>
@@ -788,40 +806,39 @@ While these feedback styles cannot be styled with CSS, you can still customize t
 
 {% example html %}
 <form>
-  <div class="row">
-    <div class="col-md-6 mb-3">
+  <div class="form-row">
+    <div class="col-md-4 mb-3">
       <label for="validationDefault01">First name</label>
       <input type="text" class="form-control" id="validationDefault01" placeholder="First name" value="Mark" required>
     </div>
-    <div class="col-md-6 mb-3">
+    <div class="col-md-4 mb-3">
       <label for="validationDefault02">Last name</label>
       <input type="text" class="form-control" id="validationDefault02" placeholder="Last name" value="Otto" required>
     </div>
+    <div class="col-md-4 mb-3">
+      <label for="validationDefaultUsername">Username</label>
+      <div class="input-group">
+        <div class="input-group-prepend">
+          <span class="input-group-text" id="inputGroupPrepend2">@</span>
+        </div>
+        <input type="text" class="form-control" id="validationDefaultUsername" placeholder="Username" aria-describedby="inputGroupPrepend2" required>
+      </div>
+    </div>
   </div>
-  <div class="row">
+  <div class="form-row">
     <div class="col-md-6 mb-3">
       <label for="validationDefault03">City</label>
       <input type="text" class="form-control" id="validationDefault03" placeholder="City" required>
-      <div class="invalid-feedback">
-        Please provide a valid city.
-      </div>
     </div>
     <div class="col-md-3 mb-3">
       <label for="validationDefault04">State</label>
       <input type="text" class="form-control" id="validationDefault04" placeholder="State" required>
-      <div class="invalid-feedback">
-        Please provide a valid state.
-      </div>
     </div>
     <div class="col-md-3 mb-3">
       <label for="validationDefault05">Zip</label>
       <input type="text" class="form-control" id="validationDefault05" placeholder="Zip" required>
-      <div class="invalid-feedback">
-        Please provide a valid zip.
-      </div>
     </div>
   </div>
-
   <button class="btn btn-primary" type="submit">Submit form</button>
 </form>
 {% endexample %}
@@ -832,17 +849,29 @@ We recommend using client side validation, but in case you require server side,
 
 {% example html %}
 <form>
-  <div class="row">
-    <div class="col-md-6 mb-3">
+  <div class="form-row">
+    <div class="col-md-4 mb-3">
       <label for="validationServer01">First name</label>
       <input type="text" class="form-control is-valid" id="validationServer01" placeholder="First name" value="Mark" required>
     </div>
-    <div class="col-md-6 mb-3">
+    <div class="col-md-4 mb-3">
       <label for="validationServer02">Last name</label>
       <input type="text" class="form-control is-valid" id="validationServer02" placeholder="Last name" value="Otto" required>
     </div>
+    <div class="col-md-4 mb-3">
+      <label for="validationServerUsername">Username</label>
+      <div class="input-group">
+        <div class="input-group-prepend">
+          <span class="input-group-text" id="inputGroupPrepend3">@</span>
+        </div>
+        <input type="text" class="form-control is-invalid" id="validationServerUsername" placeholder="Username" aria-describedby="inputGroupPrepend3" required>
+        <div class="invalid-feedback">
+          Please choose a username.
+        </div>
+      </div>
+    </div>
   </div>
-  <div class="row">
+  <div class="form-row">
     <div class="col-md-6 mb-3">
       <label for="validationServer03">City</label>
       <input type="text" class="form-control is-invalid" id="validationServer03" placeholder="City" required>
index 27995d4099f1c78cb3797d04ef26bbefbea5ba4f..3d866d95500b549311ff7a947d7cf0c7b2de3995 100644 (file)
@@ -11,32 +11,36 @@ toc: true
 Place one add-on or button on either side of an input. You may also place one on both sides of an input. **We do not support multiple form-controls in a single input group** and `<label>`s must come outside the input group.
 
 {% example html %}
-<div class="input-group">
-  <span class="input-group-addon" id="basic-addon1">@</span>
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="basic-addon1">@</span>
+  </div>
   <input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1">
 </div>
-<br>
-<div class="input-group">
+
+<div class="input-group mb-3">
   <input type="text" class="form-control" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="basic-addon2">
-  <span class="input-group-addon" id="basic-addon2">@example.com</span>
+  <div class="input-group-append">
+    <span class="input-group-text" id="basic-addon2">@example.com</span>
+  </div>
 </div>
-<br>
+
 <label for="basic-url">Your vanity URL</label>
-<div class="input-group">
-  <span class="input-group-addon" id="basic-addon3">https://example.com/users/</span>
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="basic-addon3">https://example.com/users/</span>
+  </div>
   <input type="text" class="form-control" id="basic-url" aria-describedby="basic-addon3">
 </div>
-<br>
-<div class="input-group">
-  <span class="input-group-addon">$</span>
-  <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
-  <span class="input-group-addon">.00</span>
-</div>
-<br>
-<div class="input-group">
-  <span class="input-group-addon">$</span>
-  <span class="input-group-addon">0.00</span>
+
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text">$</span>
+  </div>
   <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
+  <div class="input-group-append">
+    <span class="input-group-text">.00</span>
+  </div>
 </div>
 {% endexample %}
 
@@ -44,40 +48,66 @@ Place one add-on or button on either side of an input. You may also place one on
 
 Add the relative form sizing classes to the `.input-group` itself and contents within will automatically resize—no need for repeating the form control size classes on each element.
 
+**Sizing on the individual input group elements isn't supported.**
+
 {% example html %}
-<div class="input-group input-group-lg">
-  <span class="input-group-addon" id="sizing-addon1">@</span>
-  <input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="sizing-addon1">
+<div class="input-group input-group-sm mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="inputGroup-sizing-sm">Small</span>
+  </div>
+  <input type="text" class="form-control" aria-label="Small" aria-describedby="inputGroup-sizing-sm">
+</div>
+
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="inputGroup-sizing-default">Default</span>
+  </div>
+  <input type="text" class="form-control" aria-label="Default" aria-describedby="inputGroup-sizing-default">
 </div>
-<br>
-<div class="input-group input-group-sm">
-  <span class="input-group-addon" id="sizing-addon2">@</span>
-  <input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="sizing-addon2">
+
+<div class="input-group input-group-lg">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="inputGroup-sizing-lg">Large</span>
+  </div>
+  <input type="text" class="form-control" aria-label="Large" aria-describedby="inputGroup-sizing-sm">
 </div>
 {% endexample %}
 
-## Checkboxes and radio addons
+## Checkboxes and radios
 
 Place any checkbox or radio option within an input group's addon instead of text.
 
 {% example html %}
-<div class="row">
-  <div class="col-lg-6">
-    <div class="input-group">
-      <span class="input-group-addon">
-        <input type="checkbox" aria-label="Checkbox for following text input">
-      </span>
-      <input type="text" class="form-control" aria-label="Text input with checkbox">
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <div class="input-group-text">
+      <input type="checkbox" aria-label="Checkbox for following text input">
     </div>
   </div>
-  <div class="col-lg-6">
-    <div class="input-group">
-      <span class="input-group-addon">
-        <input type="radio" aria-label="Radio button for following text input">
-      </span>
-      <input type="text" class="form-control" aria-label="Text input with radio button">
+  <input type="text" class="form-control" aria-label="Text input with checkbox">
+</div>
+
+<div class="input-group">
+  <div class="input-group-prepend">
+    <div class="input-group-text">
+    <input type="radio" aria-label="Radio button for following text input">
     </div>
   </div>
+  <input type="text" class="form-control" aria-label="Text input with radio button">
+</div>
+{% endexample %}
+
+## Multiple inputs
+
+While multiple `<input>`s are supported visually, validation styles are only available for input groups with a single `<input>`.
+
+{% example html %}
+<div class="input-group">
+  <div class="input-group-prepend">
+    <span class="input-group-text" id="">First and last name</span>
+  </div>
+  <input type="text" class="form-control">
+  <input type="text" class="form-control">
 </div>
 {% endexample %}
 
@@ -86,61 +116,53 @@ Place any checkbox or radio option within an input group's addon instead of text
 Multiple add-ons are supported and can be mixed with checkbox and radio input versions.
 
 {% example html %}
-<div class="row">
-  <div class="col-lg-6">
-    <div class="input-group">
-      <span class="input-group-addon">
-        <input type="checkbox" aria-label="Checkbox for following text input">
-      </span>
-      <span class="input-group-addon">$</span>
-      <input type="text" class="form-control" aria-label="Text input with checkbox">
-    </div>
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <span class="input-group-text">$</span>
+    <span class="input-group-text">0.00</span>
   </div>
-  <div class="col-lg-6">
-    <div class="input-group">
-      <span class="input-group-addon">$</span>
-      <span class="input-group-addon">0.00</span>
-      <input type="text" class="form-control" aria-label="Text input with radio button">
-    </div>
+  <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
+</div>
+
+<div class="input-group">
+  <input type="text" class="form-control" aria-label="Amount (to the nearest dollar)">
+  <div class="input-group-append">
+    <span class="input-group-text">$</span>
+    <span class="input-group-text">0.00</span>
   </div>
 </div>
 {% endexample %}
 
 ## Button addons
 
-Buttons in input groups must wrapped in a `.input-group-btn` for proper alignment and sizing. This is required due to default browser styles that cannot be overridden.
-
 {% example html %}
-<div class="row">
-  <div class="col-lg-6">
-    <div class="input-group">
-      <span class="input-group-btn">
-        <button class="btn btn-secondary" type="button">Go!</button>
-      </span>
-      <input type="text" class="form-control" placeholder="Search for..." aria-label="Search for...">
-    </div>
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
   </div>
-  <div class="col-lg-6">
-    <div class="input-group">
-      <input type="text" class="form-control" placeholder="Search for..." aria-label="Search for...">
-      <span class="input-group-btn">
-        <button class="btn btn-secondary" type="button">Go!</button>
-      </span>
-    </div>
+  <input type="text" class="form-control" placeholder="" aria-label="" aria-describedby="basic-addon1">
+</div>
+
+<div class="input-group mb-3">
+  <input type="text" class="form-control" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="basic-addon2">
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
   </div>
 </div>
-<br>
-<div class="row">
-  <div class="col-lg-6 offset-lg-3">
-    <div class="input-group">
-      <span class="input-group-btn">
-        <button class="btn btn-secondary" type="button">Hate it</button>
-      </span>
-      <input type="text" class="form-control" placeholder="Product name" aria-label="Product name">
-      <span class="input-group-btn">
-        <button class="btn btn-secondary" type="button">Love it</button>
-      </span>
-    </div>
+
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+  </div>
+  <input type="text" class="form-control" placeholder="" aria-label="" aria-describedby="basic-addon1">
+</div>
+
+<div class="input-group">
+  <input type="text" class="form-control" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="basic-addon2">
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+    <button class="btn btn-outline-secondary" type="button">Button</button>
   </div>
 </div>
 {% endexample %}
@@ -148,39 +170,30 @@ Buttons in input groups must wrapped in a `.input-group-btn` for proper alignmen
 ## Buttons with dropdowns
 
 {% example html %}
-<div class="row">
-  <div class="col-lg-6">
-    <div class="input-group">
-      <div class="input-group-btn">
-        <button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          Action
-        </button>
-        <div class="dropdown-menu">
-          <a class="dropdown-item" href="#">Action</a>
-          <a class="dropdown-item" href="#">Another action</a>
-          <a class="dropdown-item" href="#">Something else here</a>
-          <div role="separator" class="dropdown-divider"></div>
-          <a class="dropdown-item" href="#">Separated link</a>
-        </div>
-      </div>
-      <input type="text" class="form-control" aria-label="Text input with dropdown button">
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</button>
+    <div class="dropdown-menu">
+      <a class="dropdown-item" href="#">Action</a>
+      <a class="dropdown-item" href="#">Another action</a>
+      <a class="dropdown-item" href="#">Something else here</a>
+      <div role="separator" class="dropdown-divider"></div>
+      <a class="dropdown-item" href="#">Separated link</a>
     </div>
   </div>
-  <div class="col-lg-6">
-    <div class="input-group">
-      <input type="text" class="form-control" aria-label="Text input with dropdown button">
-      <div class="input-group-btn">
-        <button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          Action
-        </button>
-        <div class="dropdown-menu dropdown-menu-right">
-          <a class="dropdown-item" href="#">Action</a>
-          <a class="dropdown-item" href="#">Another action</a>
-          <a class="dropdown-item" href="#">Something else here</a>
-          <div role="separator" class="dropdown-divider"></div>
-          <a class="dropdown-item" href="#">Separated link</a>
-        </div>
-      </div>
+  <input type="text" class="form-control" aria-label="Text input with dropdown button">
+</div>
+
+<div class="input-group">
+  <input type="text" class="form-control" aria-label="Text input with dropdown button">
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</button>
+    <div class="dropdown-menu">
+      <a class="dropdown-item" href="#">Action</a>
+      <a class="dropdown-item" href="#">Another action</a>
+      <a class="dropdown-item" href="#">Something else here</a>
+      <div role="separator" class="dropdown-divider"></div>
+      <a class="dropdown-item" href="#">Separated link</a>
     </div>
   </div>
 </div>
@@ -189,41 +202,36 @@ Buttons in input groups must wrapped in a `.input-group-btn` for proper alignmen
 ## Segmented buttons
 
 {% example html %}
-<div class="row">
-  <div class="col-lg-6">
-    <div class="input-group">
-      <div class="input-group-btn">
-        <button type="button" class="btn btn-secondary">Action</button>
-        <button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          <span class="sr-only">Toggle Dropdown</span>
-        </button>
-        <div class="dropdown-menu">
-          <a class="dropdown-item" href="#">Action</a>
-          <a class="dropdown-item" href="#">Another action</a>
-          <a class="dropdown-item" href="#">Something else here</a>
-          <div role="separator" class="dropdown-divider"></div>
-          <a class="dropdown-item" href="#">Separated link</a>
-        </div>
-      </div>
-      <input type="text" class="form-control" aria-label="Text input with segmented button dropdown">
+<div class="input-group mb-3">
+  <div class="input-group-prepend">
+    <button type="button" class="btn btn-outline-secondary">Action</button>
+    <button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+      <span class="sr-only">Toggle Dropdown</span>
+    </button>
+    <div class="dropdown-menu">
+      <a class="dropdown-item" href="#">Action</a>
+      <a class="dropdown-item" href="#">Another action</a>
+      <a class="dropdown-item" href="#">Something else here</a>
+      <div role="separator" class="dropdown-divider"></div>
+      <a class="dropdown-item" href="#">Separated link</a>
     </div>
   </div>
-  <div class="col-lg-6">
-    <div class="input-group">
-      <input type="text" class="form-control" aria-label="Text input with segmented button dropdown">
-      <div class="input-group-btn">
-        <button type="button" class="btn btn-secondary">Action</button>
-        <button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-          <span class="sr-only">Toggle Dropdown</span>
-        </button>
-        <div class="dropdown-menu dropdown-menu-right">
-          <a class="dropdown-item" href="#">Action</a>
-          <a class="dropdown-item" href="#">Another action</a>
-          <a class="dropdown-item" href="#">Something else here</a>
-          <div role="separator" class="dropdown-divider"></div>
-          <a class="dropdown-item" href="#">Separated link</a>
-        </div>
-      </div>
+  <input type="text" class="form-control" aria-label="Text input with segmented dropdown button">
+</div>
+
+<div class="input-group">
+  <input type="text" class="form-control" aria-label="Text input with segmented dropdown button">
+  <div class="input-group-append">
+    <button type="button" class="btn btn-outline-secondary">Action</button>
+    <button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+      <span class="sr-only">Toggle Dropdown</span>
+    </button>
+    <div class="dropdown-menu">
+      <a class="dropdown-item" href="#">Action</a>
+      <a class="dropdown-item" href="#">Another action</a>
+      <a class="dropdown-item" href="#">Something else here</a>
+      <div role="separator" class="dropdown-divider"></div>
+      <a class="dropdown-item" href="#">Separated link</a>
     </div>
   </div>
 </div>
@@ -237,7 +245,9 @@ Input groups include support for custom selects and custom file inputs. Browser
 
 {% example html %}
 <div class="input-group mb-3">
-  <label class="input-group-addon" for="inputGroupSelect01">Options</label>
+  <div class="input-group-prepend">
+    <label class="input-group-text" for="inputGroupSelect01">Options</label>
+  </div>
   <select class="custom-select" id="inputGroupSelect01">
     <option selected>Choose...</option>
     <option value="1">One</option>
@@ -253,13 +263,15 @@ Input groups include support for custom selects and custom file inputs. Browser
     <option value="2">Two</option>
     <option value="3">Three</option>
   </select>
-  <label class="input-group-addon" for="inputGroupSelect02">Options</label>
+  <div class="input-group-append">
+    <label class="input-group-text" for="inputGroupSelect02">Options</label>
+  </div>
 </div>
 
 <div class="input-group mb-3">
-  <span class="input-group-btn">
-    <button class="btn btn-secondary" type="button">Button</button>
-  </span>
+  <div class="input-group-prepend">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+  </div>
   <select class="custom-select" id="inputGroupSelect03">
     <option selected>Choose...</option>
     <option value="1">One</option>
@@ -275,9 +287,9 @@ Input groups include support for custom selects and custom file inputs. Browser
     <option value="2">Two</option>
     <option value="3">Three</option>
   </select>
-  <span class="input-group-btn">
-    <button class="btn btn-secondary" type="button">Button</button>
-  </span>
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+  </div>
 </div>
 {% endexample %}
 
@@ -285,7 +297,9 @@ Input groups include support for custom selects and custom file inputs. Browser
 
 {% example html %}
 <div class="input-group mb-3">
-  <span class="input-group-addon">Upload</span>
+  <div class="input-group-prepend">
+    <span class="input-group-text">Upload</span>
+  </div>
   <label class="custom-file">
     <input type="file" id="inputGroupFile01" class="custom-file-input" required>
     <span class="custom-file-control"></span>
@@ -297,13 +311,15 @@ Input groups include support for custom selects and custom file inputs. Browser
     <input type="file" id="inputGroupFile02" class="custom-file-input" required>
     <span class="custom-file-control"></span>
   </label>
-  <span class="input-group-addon" id="">Upload</span>
+  <div class="input-group-append">
+    <span class="input-group-text" id="">Upload</span>
+  </div>
 </div>
 
 <div class="input-group mb-3">
-  <span class="input-group-btn">
-    <button class="btn btn-secondary" type="button">Button</button>
-  </span>
+  <div class="input-group-prepend">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+  </div>
   <label class="custom-file">
     <input type="file" id="inputGroupFile03" class="custom-file-input" required>
     <span class="custom-file-control"></span>
@@ -315,9 +331,9 @@ Input groups include support for custom selects and custom file inputs. Browser
     <input type="file" id="inputGroupFile04" class="custom-file-input" required>
     <span class="custom-file-control"></span>
   </label>
-  <span class="input-group-btn">
-    <button class="btn btn-secondary" type="button">Button</button>
-  </span>
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary" type="button">Button</button>
+  </div>
 </div>
 {% endexample %}
 
index 76e09258f4e0c97ace6b8152dcf94ef48dc27cca..41fa818f3909d8ad83cebfbca1b3cb1bfd86e812 100644 (file)
@@ -224,7 +224,9 @@ Input groups work, too:
 <nav class="navbar navbar-light bg-light">
   <form class="form-inline">
     <div class="input-group">
-      <span class="input-group-addon" id="basic-addon1">@</span>
+      <div class="input-group-prepend">
+        <span class="input-group-text" id="basic-addon1">@</span>
+      </div>
       <input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1">
     </div>
   </form>
index 845f8e8b1527520d16ec913555ab2fff9163cd18..370cb3a0185ce77a519d25e2b7c3c69a6eeb3709 100644 (file)
@@ -16,6 +16,16 @@ While Beta 2 saw the bulk of our breaking changes during the beta phase, but we
 - Updated selector for input-based button groups. Instead of `[data-toggle="buttons"] { }` for style and behavior, we use the `data` attribute just for JS behaviors and rely on a new `.btn-group-toggle` class for styling.
 - Removed `.col-form-legend` in favor of a slightly improved `.col-form-label`. This way `.col-form-label-sm` and `.col-form-label-lg` can be used on `<legend>` elements with ease.
 
+### Input groups
+
+- Input group addons are now specific to their placement relative to an input. We've dropped `.input-group-addon` and `.input-group-btn` for two new classes, `.input-group-prepend` and `.input-group-append`. You must explicitly use an append or a prepend now, simplifying much of our CSS.
+
+- Validation styles are now supported, as are multiple inputs (though you can only validate one input per group).
+
+- Sizing classes must be on the parent `.input-group` and not the individual form elements.
+
+- Due to limitations in how CSS selectors work, all buttons must be the same element (e.g., `<a>` or `<button>`).
+
 ## Beta 2 changes
 
 While in beta, we aim to have no breaking changes. However, things don't always go as planned. Below are the breaking changes to bear in mind when moving from Beta 1 to Beta 2.
index a08abf232640727da123f549221e3513dd04f26f..82c6e0ee21ffe8dfa19b81d480aac4485f2874d8 100644 (file)
@@ -7,77 +7,87 @@
 .input-group {
   position: relative;
   display: flex;
+  flex-wrap: wrap; // For form validation feedback
   align-items: stretch;
   width: 100%;
 
-  .form-control {
-    // Ensure that the input is always above the *appended* addon button for
-    // proper border colors.
-    position: relative;
-    z-index: 1;
+  .form-control,
+  .custom-select,
+  .custom-file {
+    position: relative; // For focus state's z-index
     flex: 1 1 auto;
     // Add width 1% and flex-basis auto to ensure that button will not wrap out
     // the column. Applies to IE Edge+ and Firefox. Chrome does not require this.
     width: 1%;
     margin-bottom: 0;
 
-    // Bring the "active" form control to the front
-    @include hover-focus-active {
-      z-index: 2;
+    // Bring the "active" form control to the top of surrounding elements
+    &:focus {
+      z-index: 3;
+    }
+
+    + .form-control {
+      margin-left: -$input-border-width;
     }
   }
-}
 
-.input-group-addon,
-.input-group-btn,
-.input-group .form-control,
-.input-group .custom-select,
-.input-group .custom-file {
-  display: flex;
-  align-items: center;
+  .form-control,
+  .custom-select {
+    &:not(:first-child):not(:last-of-type) { @include border-radius(0); }
+    &:first-child { @include border-right-radius(0); }
+    &:last-of-type:not(:first-child) { @include border-left-radius(0); }
+  }
 
-  &:not(:first-child):not(:last-child) {
-    @include border-radius(0);
+  // Custom file inputs have more complex markup, thus requiring different
+  // border-radius overrides.
+  .custom-file {
+    &:not(:first-child):not(:last-of-type) .custom-file-control,
+    &:not(:first-child):not(:last-of-type) .custom-file-control::before { @include border-radius(0); }
+    &:first-child .custom-file-control,
+    &:first-child .custom-file-control::before { @include border-right-radius(0); }
+    &:last-of-type:not(:first-child) .custom-file-control,
+    &:last-of-type:not(:first-child) .custom-file-control::before { @include border-left-radius(0); }
   }
 }
 
-.input-group .custom-file {
+
+// Prepend and append
+//
+// While it requires one extra layer of HTML for each, dedicated prepend and
+// append elements allow us to 1) be less clever, 2) simplify our selectors, and
+// 3) support HTML5 form validation.
+
+.input-group-prepend,
+.input-group-append {
   display: flex;
   align-items: center;
-}
 
-.input-group .custom-select,
-.input-group .custom-file {
-  width: 100%;
-}
+  // Ensure buttons are always above inputs for more visually pleasing borders.
+  // This isn't needed for `.input-group-text` since it shares the same border-color
+  // as our inputs.
+  .btn {
+    position: relative;
+    z-index: 2;
+  }
 
-.input-group-addon,
-.input-group-btn {
-  white-space: nowrap;
+  .btn + .btn,
+  .btn + .input-group-text,
+  .input-group-text + .input-group-text,
+  .input-group-text + .btn {
+    margin-left: -$input-border-width;
+  }
 }
 
-// Sizing options
-//
-// Remix the default form control sizing classes into new ones for easier
-// manipulation.
-
-.input-group-lg > .form-control,
-.input-group-lg > .input-group-addon,
-.input-group-lg > .input-group-btn > .btn {
-  @extend .form-control-lg;
-}
-.input-group-sm > .form-control,
-.input-group-sm > .input-group-addon,
-.input-group-sm > .input-group-btn > .btn {
-  @extend .form-control-sm;
-}
+.input-group-prepend { margin-right: -$input-border-width; }
+.input-group-append { margin-left: -$input-border-width; }
 
 
+// Textual addons
 //
-// Text input groups
-//
+// Serves as a catch-all element for any text or radio/checkbox input you wish
+// to prepend or append to an input.
 
-.input-group-addon {
+.input-group-text {
   padding: $input-padding-y $input-padding-x;
   margin-bottom: 0; // Allow use of <label> elements by overriding our default margin-bottom
   font-size: $font-size-base; // Match inputs
   line-height: $input-line-height;
   color: $input-group-addon-color;
   text-align: center;
+  white-space: nowrap;
   background-color: $input-group-addon-bg;
   border: $input-border-width solid $input-group-addon-border-color;
   @include border-radius($input-border-radius);
 
-  // Sizing
-  &.form-control-sm {
-    padding: $input-padding-y-sm $input-padding-x-sm;
-    font-size: $font-size-sm;
-    @include border-radius($input-border-radius-sm);
-  }
-
-  &.form-control-lg {
-    padding: $input-padding-y-lg $input-padding-x-lg;
-    font-size: $font-size-lg;
-    @include border-radius($input-border-radius-lg);
-  }
-
   // Nuke default margins from checkboxes and radios to vertically center within.
   input[type="radio"],
   input[type="checkbox"] {
 }
 
 
+// Sizing
 //
-// Reset rounded corners
-//
-
-.input-group .form-control:not(:last-child),
-.input-group .custom-select:not(:last-child),
-.input-group .custom-file:not(:last-child) .custom-file-control::before,
-.input-group-addon:not(:last-child),
-.input-group-btn:not(:last-child) > .btn,
-.input-group-btn:not(:last-child) > .btn-group > .btn,
-.input-group-btn:not(:last-child) > .dropdown-toggle,
-.input-group-btn:not(:first-child) > .btn:not(:last-child):not(.dropdown-toggle),
-.input-group-btn:not(:first-child) > .btn-group:not(:last-child) > .btn {
-  @include border-right-radius(0);
-}
+// Remix the default form control sizing classes into new ones for easier
+// manipulation.
 
-.input-group-addon:not(:last-child) {
-  border-right: 0;
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-prepend > .input-group-text,
+.input-group-lg > .input-group-append > .input-group-text,
+.input-group-lg > .input-group-prepend > .btn,
+.input-group-lg > .input-group-append > .btn {
+  @extend .form-control-lg;
 }
 
-.input-group .form-control:not(:first-child),
-.input-group .custom-select:not(:first-child),
-.input-group .custom-file:not(:first-child) .custom-file-control,
-.input-group-addon:not(:first-child),
-.input-group-btn:not(:first-child) > .btn,
-.input-group-btn:not(:first-child) > .btn-group > .btn,
-.input-group-btn:not(:first-child) > .dropdown-toggle,
-.input-group-btn:not(:last-child) > .btn:not(:first-child),
-.input-group-btn:not(:last-child) > .btn-group:not(:first-child) > .btn {
-  @include border-left-radius(0);
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-prepend > .input-group-text,
+.input-group-sm > .input-group-append > .input-group-text,
+.input-group-sm > .input-group-prepend > .btn,
+.input-group-sm > .input-group-append > .btn {
+  @extend .form-control-sm;
 }
 
-.form-control,
-.custom-select,
-.custom-file {
-  + .input-group-addon:not(:first-child) {
-    border-left: 0;
-  }
-}
 
+// Prepend and append rounded corners
 //
-// Button input groups
-//
-
-.input-group-btn {
-  position: relative;
-  align-items: stretch;
-  // Jankily prevent input button groups from wrapping with `white-space` and
-  // `font-size` in combination with `inline-block` on buttons.
-  font-size: 0;
-  white-space: nowrap;
-
-  // Negative margin for spacing, position for bringing hovered/focused/actived
-  // element above the siblings.
-  > .btn {
-    position: relative;
+// These rulesets must come after the sizing ones to properly override sm and lg
+// border-radius values when extending. They're more specific than we'd like
+// with the `.input-group >` part, but without it, we cannot override the sizing.
 
-    + .btn {
-      margin-left: (-$input-border-width);
-    }
+.input-group > .input-group-prepend > .btn,
+.input-group > .input-group-prepend > .input-group-text {
+  // All prepended buttons have no right border-radius
+  @include border-right-radius(0);
 
-    // Bring the "active" button to the front
-    @include hover-focus-active {
-      z-index: 2;
-    }
+  + .btn,
+  + .input-group-text {
+    @include border-left-radius(0);
   }
+}
 
-  &:first-child > .btn + .btn {
-    margin-left: 0;
+// We separate out the button and input resets here because `.input-group-text`
+// can be any HTML element, but buttons are always inputs, buttons, or anchors.
+.input-group > .input-group-append {
+  // Everything but the last one have no rounded corners
+  .btn:not(:last-of-type),
+  .input-group-text:not(:last-child) {
+    @include border-radius(0);
   }
 
-  // Negative margin to only have a single, shared border between the two
-  &:not(:last-child) {
-    > .btn,
-    > .btn-group {
-      margin-right: (-$input-border-width);
-    }
-  }
-  &:not(:first-child) {
-    > .btn,
-    > .btn-group {
-      z-index: 1;
-      // remove nagative margin ($input-border-width) to solve overlapping issue with button.
-      margin-left: 0;
-
-      // When input is first, overlap the right side of it with the button(-group)
-      &:first-child {
-        margin-left: (-$input-border-width);
-      }
-
-      // Because specificity
-      @include hover-focus-active {
-        z-index: 2;
-      }
-    }
+  .btn:last-of-type,
+  .input-group-text:last-child {
+    @include border-left-radius(0);
   }
 }
index b7e664db7335e3a825ecbf71902c9779a709dc3c..470f80c15c4237984c492475ee41db7c890e9d83 100644 (file)
@@ -30,6 +30,7 @@
 
   .#{$state}-feedback {
     display: none;
+    width: 100%;
     margin-top: $form-feedback-margin-top;
     font-size: $form-feedback-font-size;
     color: $color;