Skip to main content

Text Input

A text input is an interactive element that allows users to enter and edit text within a user interface.

Overview

GitHub Workflow Status GitHub Workflow Status

pie-text-input is a Web Component built with Lit, providing a simple and accessible text input for web applications.

This component integrates easily with various frontend frameworks and can be customised through a set of properties.

Installation

To install pie-text-input in your application via npm or yarn:

npm i @justeattakeaway/pie-webc
yarn add @justeattakeaway/pie-webc

Props

PropOptionsDescriptionDefault
assistiveTextstring
Allows assistive text to be displayed below the input element. Must be provided if using a non-default status.undefined
autoFocustrue
false
If true, the input will be focused on the first render. No more than one element in the document or dialog may have the autofocus attribute. If applied to multiple elements the first one will receive focus. See MDN for more information.false
autocompletestring
Allows the user to enable or disable autocomplete functionality on the input field. See MDN for more information and values.undefined
defaultValuestring
During a form reset, the default value will replace the current value. This prop is not normally needed.undefined
disabledtrue
false
When true, the user cannot edit or interact with the control.false
inputmode"none"
"text"
"tel"
"url"
"email"
"numeric"
"decimal"
"search"
Provides a hint to browsers as to the type of virtual keyboard configuration to use when editing this element. See MDN for more information.undefined
maxnumber
The maximum value of the input. Only applies when type is number. If the value provided is higher, the input is invalid.undefined
maxlengthnumber
Maximum length (number of characters) of value. Only applies to types: text, url, tel, email, and password.undefined
minnumber
The minimum value of the input. Only applies when type is number. If the value provided is lower, the input is invalid.undefined
minlengthnumber
Minimum length (number of characters) of value. Only applies to types: text, url, tel, email, and password.undefined
namestring
The name of the input (used as a key/value pair with value). This is required in order to work properly with forms.undefined
patternstring
Specifies a regular expression the form control's value should match.undefined
placeholderstring
The placeholder text to display when the input is empty. Only applies to types: text, url, tel, email, and password.undefined
readonlytrue
false
When true, the user cannot edit the control. Not the same as disabled. See MDN for more information.false
requiredtrue
false
If true, the input is required to have a value before submitting the form. If there is no value, then the component validity state will be invalid. Important note: This will not prevent the form submission.false
size"small"
"medium"
"large"
The size of the input field."medium"
status"default"
"error"
"success"
The status of the input component / assistive text. If you use a non-default status you must also provide assistiveText for accessibility purposes."default"
stepnumber
An optional amount that value should be incremented or decremented by when using the up and down arrows in the input. Only applies when type is number.undefined
type"text"
"number"
"password"
"url"
"email"
"tel"
The type of HTML input to render."text"
valuestring
The value of the input (used as a key/value pair in HTML forms with name).""

Slots

SlotDescription
leadingIcon
An icon to display at the start of the input.
Do not use at the same time as leadingText.
leadingText
Short text to display at the start of the input.
Wrap the text in a <span>.
Do not use at the same time as leadingIcon.
trailingIcon
An icon to display at the end of the input.
Do not use at the same time as trailingText.
trailingText
Short text to display at the end of the input.
Wrap the text in a <span>.
Do not use at the same time as trailingIcon.

Events

EventDescription
change
Fires when the input loses focus after the value has been changed.
input
Fires when the input value is changed.

Importing and usage in templates

For HTML and Vue:

// import as module into a js file that will be loaded on the page where the component is used.
import '@justeattakeaway/pie-webc/components/text-input.js';
<pie-text-input
    autocomplete="on"
    autoFocus
    inputmode="text"
    maxlength="8"
    minlength="4"
    name="myinput"
    pattern="[a-z]{4,8}"
    placeholder="Please enter a value"
    readonly
    type="text"
    value="">
</pie-text-input>

For React Applications:

import { PieTextInput } from '@justeattakeaway/pie-webc/react/text-input.js';

<PieTextInput
    autocomplete="on"
    autoFocus
    inputmode="text"
    maxlength={8}
    minlength={4}
    name="myinput"
    pattern="[a-z]{4,8}"
    placeholder="Please enter a value"
    readonly
    type="text"
    value="">
</PieTextInput>
// React templates (using Next 13 and SSR)
import { PieTextInput } from '@justeattakeaway/pie-text-input/dist/react';

<PieTextInput
  autocomplete="on"
  autoFocus
  inputmode="text"
  maxlength={8}
  minlength={4}
  name="myinput"
  pattern="[a-z]{4,8}"
  placeholder="Please enter a value"
  readonly
  type="text"
  value="">
</PieTextInput>

Types

The text input accepts various values for the type property, allowing control over input behaviour. These are mostly standard HTML input types. For most use cases, the default type of text will suffice. It is important to note that setting the type to number does not guarantee the prevention of non-numeric characters being entered. This behaviour, which is consistent with native HTML inputs, allows some non-numeric characters such as e,+, -, and ..

While different types can influence the virtual keyboard on mobile devices, this can also be controlled using the inputmode property.

If your application requires specific formatting and needs to control which characters can be entered, or if you need to provide auto-formatting (such as adding spaces to a credit card number), you will need to handle this in your application code. You can listen to the input and change events emitted by the text input component to manage these requirements.

Slots usage

You can provide icons or text to sit before or after the input value. When using the leadingText or trailingText slots, wrap the text in a <span> and limit it to 2-3 characters at most. Do not use leadingText with leadingIcon or trailingText with trailingIcon simultaneously.

For icons in the leadingIcon or trailingIcon slots, ensure you use the icon components from our web component icon library. Other icons are not guaranteed to work and will not be supported.

HTML

<pie-text-input
  class="form-field"
  id="username"
  data-test-id="username"
  name="username"
  type="text">
  <icon-user slot="leadingIcon"></icon-user>
  <span slot="trailingText">##</span>
</pie-text-input>

Vue

<pie-text-input
  :value="username"
  @input="username = $event.target.value"
  class="form-field"
  id="username"
  data-test-id="username"
  name="username"
  type="text">
  <icon-user slot="leadingIcon"></icon-user>
  <span slot="trailingText">##</span>
</pie-text-input>

React

<PieTextInput
  className="form-field"
  id="username"
  data-test-id="username"
  name="username"
  value={username}
  onInput={handleUsernameInput as any}
  type="text">
  <IconUser slot="leadingIcon"></IconUser>
  <span slot="trailingText">##</span>
</PieTextInput>

Forms usage

It is essential that when using the text input inside of a form, you provide a name attribute. HTML forms create key/value pairs for input data based on the name attribute, which is crucial for native form submission.

Validation

The text input component utilizes the constraint validation API to provide a queryable validity state for consumers. This means that the component's validity can be checked via a validity getter.

Example:

const textInput = document.querySelector('pie-text-input');
console.log(textInput.validity.valid);

This getter can be useful for reducing the amount of validation code in your application. For example, if you want to create a text input that should be at least 2 characters long, at most 5 characters long, and requires a value, you can set the minlength, maxlength, and required properties on the component. You can then check the validity of the input in your application code:

<pie-text-input
  id="my-input"
  name="my-input"
  minlength="2"
  maxlength="5"
  required></pie-text-input>
const textInput = document.querySelector('pie-text-input');
const isValid = textInput.validity.valid;

// We could use this to drive the status and assistiveText properties on our input (this would likely be inside a submit event handler in a real application)
if (!isValid) {
  textInput.status = 'error';
  textInput.assistiveText = 'Please enter a value between 2 and 5 characters long';
}

These concepts work just as well inside a Vue or React application. Below is a similar implementation for validating a number input in a React application.

// Very simplified example
const [favouriteNumber, setFavouriteNumber] = useState('');
const [favouriteNumberValidationMessage, setFavouriteNumberValidationMessage] = useState('');

const favouriteNumberRef = useRef<HTMLInputElement>(null);

const handleFavouriteNumberInput = (event: InputEvent) => {
    setFavouriteNumber((event.target as HTMLInputElement).value);
};

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    let validationMessage = '';
    const inputElement = favouriteNumberRef.current;

    if (inputElement) {
        if (inputElement.validity.rangeUnderflow) {
            validationMessage = 'The favourite number is too low. Please pick a number between -5 and 200.';
        } else if (inputElement.validity.rangeOverflow) {
            validationMessage = 'The favourite number is too high. Please pick a number between -5 and 200.';
        }
    }

    setFavouriteNumberValidationMessage(validationMessage);
};
// Very simplified example
<form id="testForm" onSubmit={handleSubmit} novalidate>
  <PieFormLabel id="favouriteNumberLabel" for="favouriteNumber">
      Favourite Number:
  </PieFormLabel>
  <PieTextInput
      aria-labelledby="favouriteNumberLabel"
      id="favouriteNumber"
      data-test-id="favouriteNumber"
      name="favouriteNumber"
      min={-5}
      max={200}
      value={favouriteNumber}
      onInput={handleFavouriteNumberInput as any}
      type="number"
      ref={favouriteNumberRef}
      assistiveText={favouriteNumberValidationMessage}
      status={favouriteNumberValidationMessage ? 'error' : 'success'}>
      <IconNumberSymbol slot="leadingIcon"></IconNumberSymbol>
  </PieTextInput>

  <PieButton data-test-id="submit-btn" type="submit">Submit</PieButton>
</form>

Displaying error messages

As mentioned earlier, we suggest consumers disable native HTML validation using the novalidate attribute on the form element. This will prevent the browser from displaying its own validation messages, allowing you to control the validation experience for your users.

To display validation messages, you can use the assistiveText and status properties on the text input component. The assistiveText property is used to display a message below the input, and the status property is used to set the visual state of the input. The status property can be set to error or success, or you can omit providing a status to display the assistive text in a neutral state.

<pie-text-input
  name="firstName"
  assistiveText="Please provide a first name"
  status="error">
</pie-text-input>

Displaying success messages works in the same way, but with the status property set to success.

<pie-text-input
  name="firstName"
  assistiveText="First name provided"
  status="success">
</pie-text-input>

Labelling

Please use the form label component for adding a label to the text input. Similar to native HTML, the label should be a sibling of the input component and reference the input's id attribute using the for attribute.

The usage of aria-labelledby is very important so that screen readers will announce the label when the input is focused. This is especially important for users who rely on screen readers to navigate the web.

<pie-form-label id="first-name-label" for="first-name">First name:</pie-form-label>
<pie-text-input aria-labelledby="first-name-label" id="first-name" name="first-name"></pie-text-input>

If you do not need to use a visual label, you must still provide an aria-label attribute to the text input. This is important for screen reader users as it will announce the purpose of the input when it is focused, even if a visual label is not used.

<pie-text-input aria-label="First name" name="first-name"></pie-text-input>

Changelog