TextField
A basic
TextField
implementation using Formik and Yup to validate a required email
text input.A basic
TextField
implementation includes an input
with a required label. Descriptive helperText
can be added.Disabled states should be used with caution.
Content can be prepended or appended
import React, { useState } from 'react'import { Button, FormLayout, IconButton, TextField } from '@gusto/workbench'import { Hide, Search, Show } from '@gusto/workbench-icons'export const WithBeforeAfterContent = () => {const [type, setType] = useState('password')const [value, setValue] = useState('payroll')return (<FormLayoutfields={<><TextFieldlabel="Full name"autoComplete="name"name="name"before="Mx."/><TextFieldlabel="Full name"autoComplete="name"name="name"after="Esquire"/><TextFieldlabel="Full name"autoComplete="name"name="name"before="Mx."after="Esquire"/><TextFieldlabel="Password"autoComplete="current-password"name="password"type={type}after={// Clickable or interactable elements must override the// default `pointer-events: none;` by setting `pointer-events: auto;`.// You may also want to remove the element from the tab order using `tabIndex={-1}`<IconButtonaria-label={type === 'password' ? `Show password` : `Hide password`}title={type === 'password' ? 'Show' : 'Hide'}style={{ pointerEvents: 'auto' }}edge="end"onClick={() =>setType(type === 'password' ? 'text' : 'password')}>{type === 'password' ? <Show /> : <Hide />}</IconButton>}defaultValue="password1!"/><TextFieldtype="search"name="search"label="Search"before={<Search />}value={value}onChange={e => setValue(e.target.value)}after={value ? (<ButtononClick={() => setValue('')}style={{ pointerEvents: 'auto' }}variant="link">clear</Button>) : null}/></>}/>)}
The
CharacterCount
component can be added to fields.Any valid HTML attribute for the
<input/>
tag can be passed through TextField
. In this example, we leverage various intrinsic HTML attributes to alter the behavior of the <input/>
.Setting the appropriate
type
on the input provides the browser with a hint as to which virtual keyboard would be most helpful when entering data in this field (relevant in mobile devices).The size
and placeholder
, min
, and max
are commonly used to set parameters for the data the field can accept.Use the
format
prop to apply a visual mask to the input. As the user types, the mask will ensure the user is applying the correct format. Workbench supports a variety of alphanumeric masks, including phone and social security numbers.Optional fields should be explicitly called out using the
optional
propIt may sometimes be necessary to hide labels, but label text must still be made available for screen readers. This example uses the visuallyHideLabel
prop to visually hide the label.
Name | Type | Default | Description |
---|---|---|---|
after | ReactNode | - | Content shown after the input value. By default this content is not interactive and will ignore pointer events. Any interactive elements must be styled with pointer-events: auto; |
before | ReactNode | - | Content shown before the input value. By default this content is not interactive and will ignore pointer events. Any interactive elements must be styled with pointer-events: auto; |
children | ReactNode | - | The content of the component. This content will be rendered as a sibling of the native input element. |
component | ReactNode | - | Component override for the input element |
counter | ReactNode | - | Indicator of a limit placed on a field, e.g. maximum character count or remaining hours. |
fit | content container | - | Determines the point of reference for the width of the component. If set to content, the size will be set by the size of the input . If set to container, the size will expand to fit the containing element. |
format | string | - | A combination of ‘static‘ and ‘replacement‘ characters to create a mask for the input value
format="+\\9 (999)-999-9999" will allow +9 (123)-456-7890 ) |
helperText | ReactNode | - | A brief description or hint for the input ; can be used to link to an external resource. |
id | string | - | The id of the input element |
invalid | boolean | - | If true , the field will be shown in an invalid state |
label Required | string | - | Label associated with the input |
name Required | string | - | Name of the input . Submitted with the form as part of a name/value pair. |
optional | boolean | - | Used to indicate the field is optional |
securityMask | boolean | - | Add security masking to the input value. When true , the input value will be masked when not focused. |
validationText | ReactNode | - | Validation message associated with the input |
- Always provide a non-empty
label
for the TextField - Avoid changing
tabindex
as this will affect the ability for keyboard users to navigate sequentially through the form
The following testing snippet(s) offer suggestions for testing the component using React Testing Library with occasional help from Jest.
// BASIC TESTSrender(<TextField label="Label" helperText="Helper text" />);const input = screen.getByLabelText('Label');expect(input).toHaveAccessibleDescription('Helper text');userEvent.type(input, 'Hello');expect(input).toHaveDisplayValue('Hello');// TESTING VALIDITYrender(<TextField label="Label" invalid validationText="Validation text" />);const input = screen.getByLabelText('Label');expect(input).toBeInvalid(); // or expect(input).not.toBeValid();expect(input).toHaveAccessibleDescription('Validation text');// TESTING MULTIPLE DESCRIPTIVE ELEMENTSrender(<TextFieldlabel="Label"helperText="Helper text"optionalvalidationText="Validation text"/>,);const input = screen.getByLabelText('Label');expect(input).toHaveAccessibleDescription(expect.stringContaining('(optional)'));expect(input).toHaveAccessibleDescription(expect.stringContaining('Helper text'));expect(input).toHaveAccessibleDescription(expect.stringContaining('Validation text'));// or all at once:expect(input).toHaveAccessibleDescription('(optional) Helper text Validation text');// TESTING BEFORE AND AFTERrender(<TextField label="Label" before="Before" after="After" />);const inputContainer = screen.getByLabelText('Label').parentElement as HTMLDivElement;expect(container).toHaveTextContent('Before');expect(container).toHaveTextContent('After');