Props

name type default description
className string Class name for the input element. This should include any BEM modifier classes you wish to use.
type valid HTML type for text-based input element ‘text’

The type prop must be one of the the allowed input types:

color
date
datetime
datetime-local
email
month
number
password
search
tel
text
time
url
week

Valid HTML attributes and event handlers for the input element may be safely passed as additional props. Passing a prop that is not a legal DOM attribute will cause React to trigger an unknown prop warning.

Note that there are several attributes that work differently between React and HTML. In these cases, attributes should be passed the React-y way.

Modifiers

class default responsive notes
TextInput--small false true
TextInput--medium true true
TextInput--large false true
TextInput--has-error false false
<!-- Medium -->
<input type="text" class="TextInput" placeholder="Placeholder text" />

<!-- Small -->
<input type="text" class="TextInput--small TextInput" placeholder=".TextInput--small" />

<!-- Large -->
<input type="text" class="TextInput--large TextInput" placeholder=".TextInput--large" />

<!-- Disabled -->
<input type="text" class="TextInput" placeholder="Can’t touch this." disabled="" />

<!-- Error -->
<input type="text" class="TextInput--has-error TextInput" placeholder="Placeholder text" value="Something went horribly wrong." />

<!-- Password -->
<input type="password" class="TextInput" placeholder="Password goes here." />

<!-- Responsive -->
<input type="text" class="TextInput--small TextInput--medium-sm TextInput--large-md TextInput" placeholder="Resize me!" />

import * as React from 'react';
import classes from 'classnames';

const INPUT_TYPES = {
  color: 'color',
  date: 'date',
  datetime: 'datetime',
  'datetime-local': 'datetime-local',
  email: 'email',
  month: 'month',
  number: 'number',
  password: 'password',
  search: 'search',
  tel: 'tel',
  text: 'text',
  time: 'time',
  url: 'url',
  week: 'week',
};

function validateType(type) {
  if (INPUT_TYPES[type]) {
    return type;
  }

  throw new Error(`Unknown input type: ${type}`);
}

function TextInput(props) {
  const { className, type, ...htmlProps } = props;
  return (
    <input
      className={classes(className, 'TextInput')}
      type={validateType(type)}
      {...htmlProps}
    />
  );
}

TextInput.defaultProps = {
  type: 'text',
};

export default TextInput;
/* Medium */
{
  "placeholder": "Placeholder text"
}

/* Small */
{
  "placeholder": ".TextInput--small",
  "className": "TextInput--small"
}

/* Large */
{
  "placeholder": ".TextInput--large",
  "className": "TextInput--large"
}

/* Disabled */
{
  "placeholder": "Can’t touch this.",
  "disabled": true
}

/* Error */
{
  "placeholder": "Placeholder text",
  "className": "TextInput--has-error",
  "defaultValue": "Something went horribly wrong."
}

/* Password */
{
  "placeholder": "Password goes here.",
  "type": "password"
}

/* Responsive */
{
  "placeholder": "Resize me!",
  "className": "TextInput--small TextInput--medium-sm TextInput--large-md"
}

  • Content:
    // scss-lint:disable SelectorFormat ElsePlacement
    
    @mixin _text-input-padding($t-step: 0, $x-step: 0, $b-step: 0) {
      // Reduce all padding values by 2px to account for border width
      // Fudge top padding by +1px and bottom by -1px for better text alignment
      $top: modular-scale-px($t-step) - $border-width + 1px;
      $bottom: modular-scale-px($b-step) - $border-width - 1px;
      $horizontal: modular-scale-px($x-step) - $border-width;
      padding: $top $horizontal $bottom;
    }
    
    @mixin text-input-sizer($size: 'medium') {
      @if $size == 'small' {
        @include _text-input-padding(-6, -3, -5);
        font-size: $font-size-2;
      }
    
      @else if $size == 'medium' {
        @include _text-input-padding(-3, 0, -2);
        font-size: $font-size-3;
      }
    
      @else if $size == 'large' {
        @include _text-input-padding(0, 2, 1);
        font-size: $font-size-4;
      }
    }
    
    .TextInput {
      @include text-input-sizer;
      -webkit-appearance: none;
      border: $border-width solid $gray-300;
      border-radius: $border-radius;
      color: $text-color-primary;
      line-height: $line-height-base;
      width: 100%;
    
      &::placeholder {
        color: $text-color-hint;
        // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
        opacity: 1;
      }
    }
    
    .TextInput:focus {
      border-color: $blue-100;
      box-shadow: 0 0 11px rgba($blue-100, $alpha-500);
      outline: 0;
    }
    
    .TextInput:disabled,
    .TextInput[readonly] {
      background: $gray-200;
      border-color: $gray-200;
      color: $text-color-hint;
      cursor: not-allowed;
      opacity: 1; // some browsers (e.g. iOS Safari) reduce opacity
    }
    
    .TextInput--has-error,
    .FormGroup--has-error .TextInput {
      border-color: $red;
    
      &.TextInput:focus {
        box-shadow: 0 0 11px rgba($red-100, $alpha-600);
      }
    }
    
    //
    // Sizers
    //
    
    @if $enable-responsive-form-components {
      @each $breakpoint in map-keys($grid-breakpoints) {
        @include media-breakpoint-up($breakpoint) {
          $suffix: breakpoint-suffix($breakpoint, $grid-breakpoints);
          // Sacrificing some BEM purity and styling .TextInput nested inside
          // .FormGroup here to avoid having tons of duplicate styles
          .TextInput--medium#{$suffix},
          .FormGroup--medium#{$suffix} .TextInput {
            @include text-input-sizer;
          }
    
          .TextInput--small#{$suffix},
          .FormGroup--small#{$suffix} .TextInput {
            @include text-input-sizer('small');
          }
    
          .TextInput--large#{$suffix},
          .FormGroup--large#{$suffix} .TextInput {
            @include text-input-sizer('large');
          }
        }
      }
    } @else {
      .TextInput--small { @include text-input-sizer('small'); }
      .TextInput--large { @include text-input-sizer('large'); }
    }
    
  • URL: /components/raw/text-input/_text_input.scss
  • Filesystem Path: library/components/text_input/_text_input.scss
  • Size: 2.6 KB