Props

name type default description
className string Class name for the root element. This should include any BEM modifier classes you wish to use.
controlId string The id for the input element described by the form group’s label text. See below for notes on controlId and accessibility.
label string Label for form group.
hint string Helper text for form group.
error string Error message for form group. If present, form group will be rendered in an error state.

Modifiers

class default responsive notes
FormGroup--small false true
FormGroup--medium true true
FormGroup--large false true
FormGroup--has-error false false If the component has a truthy error prop, this modifier is applied automatically.

Usage

With a single control input

Passing the form group both a label and a controlId will render a <label> element with the controlId as its for attribute. This pattern should be used for form groups with a visible label and a single text-based input.

Javascript:

<FormGroup
  controlId="dob"
  label="Birthday"
  hint="When were you born?"
>
  <input type="text" id="dob"/>
</FormGroup>

Rendered markup:

<div class="FormGroup">
    <label for="dob" class="FormGroup__label">Birthday</label>
    <input type="text" id="dob"/>
    <div class="FormGroup__hint">When were you born?</div>
</div>

If the child input has its own label, the controlId prop should be omitted.

Javascript:

<FormGroup label="Subscribe">
  <label for="subscribe-true">Send me updates</label>
  <input type="checkbox" value="yes" id="subscribe-true"/>
</FormGroup>

Rendered markup:

<div class="FormGroup">
    <label class="FormGroup__label">Subscribe</label>
    <label for="subscribe-true">Send me updates</label>
    <input type="checkbox" value="yes" id="subscribe-true"/>
</div>

With multiple inputs

If the form group has multiple inputs, the controlId prop can be omitted. In these cases, the child inputs should include an aria-label or aria-labelledby attribute to ensure accessibility:

Javascript:

<FormGroup label="When are you available?">
  <input type="text" aria-label="Start time"/>
  <input type="text" aria-label="End time"/>
</FormGroup>

Rendered markup:

<div class="FormGroup">
    <label class="FormGroup__label">When are you available?</label>
    <input type="text" aria-label="Start time"/>
    <input type="text" aria-label="End time"/>
</div>
<div class="FormGroup--small FormGroup FormGroup--has-error">
    <label for="error1" class="FormGroup__label">Error state (small)</label>
    <input type="text" class="TextInput" id="error1" placeholder="Placeholder text" />
    <div class="FormGroup__error">Error message</div>
    <div class="FormGroup__hint">Helper text</div>
</div>
import * as React from 'react';
import classes from 'classnames';

import TextInput from '../text_input/text_input.jsx';

class FormGroup extends React.Component {
  renderChildren() {
    // Preview environment won't have a child prop, so we have to supply a default one here:
    if (this.props.__preview) {
      return (
        <TextInput id={this.props.controlId} placeholder="Placeholder text" />
      );
    }
    return this.props.children;
  }

  renderHint() {
    return (
      !!this.props.hint && (
        <div className="FormGroup__hint">{this.props.hint}</div>
      )
    );
  }

  renderError() {
    return (
      !!this.props.error && (
        <div className="FormGroup__error">{this.props.error}</div>
      )
    );
  }
  renderLabel() {
    return (
      !!this.props.label && (
        <label htmlFor={this.props.controlId} className="FormGroup__label">
          {this.props.label}
        </label>
      )
    );
  }

  render() {
    return (
      <div
        className={classes(this.props.className, 'FormGroup', {
          'FormGroup--has-error': !!this.props.error,
        })}
      >
        {this.renderLabel()}
        {this.renderChildren()}
        {this.renderError()}
        {this.renderHint()}
      </div>
    );
  }
}

export default FormGroup;
{
  "__preview": true,
  "label": "Error state (small)",
  "hint": "Helper text",
  "className": "FormGroup--small",
  "controlId": "error1",
  "error": "Error message"
}
  • Content:
    // scss-lint:disable SelectorFormat ElsePlacement
    @mixin form-group-sizer($size: 'medium') {
      @if $size == 'small' {
        .FormGroup__label {
          @include text-1($font-weight-bold);
          margin-bottom: $spacer-1;
        }
    
        .FormGroup__error {
          @include text-1;
        }
      }
    
      @else if $size == 'medium' {
        .FormGroup__label {
          @include text-2($font-weight-bold);
          margin-bottom: $spacer-2;
        }
    
        .FormGroup__error {
          @include text-2;
          color: $brand-danger;
          margin-top: $spacer-2;
    
          &::before {
            content: '✘ '; // TODO: replace with SVG icon
            display: inline;
          }
        }
    
        .FormGroup__hint {
          @include text-1;
          color: $text-color-secondary;
          margin-top: $spacer-2;
        }
      }
    
      @else if $size == 'large' {
        .FormGroup__label {
          @include text-4($font-weight-bold);
        }
    
        .FormGroup__error {
          @include text-3;
        }
    
        .FormGroup__hint {
          @include text-2;
        }
      }
    }
    
    //
    // Sizers
    //
    
    @include form-group-sizer;
    
    @if $enable-responsive-form-components {
      @each $breakpoint in map-keys($grid-breakpoints) {
        @include media-breakpoint-up($breakpoint) {
          $suffix: breakpoint-suffix($breakpoint, $grid-breakpoints);
          .FormGroup--small#{$suffix} { @include form-group-sizer('small'); }
          .FormGroup--medium#{$suffix} { @include form-group-sizer; }
          .FormGroup--large#{$suffix} { @include form-group-sizer('large'); }
        }
      }
    } @else {
      .FormGroup--small { @include form-group-sizer('small'); }
      .FormGroup--large { @include form-group-sizer('large'); }
    }
    
  • URL: /components/raw/form-group/_form_group.scss
  • Filesystem Path: library/components/form_group/_form_group.scss
  • Size: 1.6 KB