Skip to content
v2.5.0
English
Русский
Documentation

HelperText

HelperText renders supporting field copy such as hints, usage guidance, and validation-adjacent messages.

At least 8 characters.

helper-text.tsx · 14 lines
import {
  HelperText,
  Label,
  TextField,
  TextFieldInput,
} from '@vega-ui/react';

<div>
  <Label htmlFor='preview-helper-password'>Password</Label>
  <TextField>
    <TextFieldInput id='preview-helper-password' type='password' defaultValue='secret' aria-describedby='preview-helper-hint' />
  </TextField>
Browser support
Widely available
  • Chrome 111
  • Edge 111
  • Firefox 113
  • Safari 15.4
  • Safari on iOS 15.4
Bundle size
Tested in
9 tests

Summary

HelperText renders supporting field copy such as hints, usage guidance, and validation-adjacent messages. It reuses the Text typography layer and adds semantic helper or error coloring for field-level support content.

Imports

import { HelperText, type HelperTextProps } from '@vega-ui/react';

Exported Types

  • HelperTextProps

Basic Usage

field-hint.tsx · 17 lines
import { HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { useId } from 'react';

export default function FieldHint() {
  const id = useId();
  const hintId = `${id}-hint`;

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%' }}>
      <Label htmlFor={id}>Recovery email</Label>
      <TextField>
        <TextFieldInput id={id} type='email' autoComplete='email' aria-describedby={hintId} />

Variants

  • Size: sm, md, lg
  • State: default helper copy or error
  • Placement: below fields, selectors, or grouped controls

Edge Cases

  • error changes tone, but the field itself still needs its own invalid state.
  • Helper copy should stay short enough to scan with the associated control.
  • Long explanatory text usually belongs in body copy, not helper text.
  • The component supports one control or one grouped field concept; it should not become a dumping ground for unrelated form instructions.

Common Mistakes

  • Repeating the same content already present in the label.
  • Using helper text as the only error indicator.
  • Writing policy or legal paragraphs in helper text style.

Examples

Basic

Basic: hint linked to a field

Give HelperText an id and reference it from the input's aria-describedby; otherwise screen readers never connect the hint to the field. The hint is read after the label when the input gets focus.

field-hint.tsx · 17 lines
import { HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { useId } from 'react';

export default function FieldHint() {
  const id = useId();
  const hintId = `${id}-hint`;

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%' }}>
      <Label htmlFor={id}>Recovery email</Label>
      <TextField>
        <TextFieldInput id={id} type='email' autoComplete='email' aria-describedby={hintId} />

Controlled/Stateful

Controlled/Stateful: remaining characters

The count is derived from the value on each keystroke and turns into an error tone at the limit. Announcing every keystroke would be noisy, so a separate hidden status region speaks only in the last ten characters.

remaining-characters.tsx · 30 lines
import { HelperText, Label, TextField, TextFieldInput, VisuallyHidden } from '@vega-ui/react';
import { useId, useState } from 'react';

const MAX_LENGTH = 50;

export default function RemainingCharacters() {
  const id = useId();
  const [subject, setSubject] = useState('Your March invoice is ready');
  const remaining = MAX_LENGTH - subject.length;
  const message = remaining === 1 ? '1 character left' : `${remaining} characters left`;

  return (

Form/Integration

Form/Integration: hint for a group of controls

One hint for several checkboxes belongs to the group: the Fieldset references it with aria-describedby. On submit, FormData.getAll collects every checked channel.

group-hint.tsx · 47 lines
import {
  Button,
  Checkbox,
  CheckboxCheckedIcon,
  CheckboxIndicator,
  CheckboxInput,
  Fieldset,
  FieldsetLegend,
  HelperText,
  Text,
} from '@vega-ui/react';
import { FormEvent, useId, useState } from 'react';

Layout/Overlay

Layout/Overlay: reserved space for the message

The message slot keeps a minHeight of two lines, so an appearing error does not push the next row down or misalign fields that sit side by side.

reserved-message-space.tsx · 35 lines
import { HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { useId, useState } from 'react';

export default function ReservedMessageSpace() {
  const id = useId();
  const [code, setCode] = useState('');
  const invalid = code !== '' && !/^[A-Z]{3}-\d{4}$/.test(code);

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: 'var(--spacing-8)', width: '100%' }}>
      <div style={{ display: 'grid', gap: 'var(--spacing-3)', alignContent: 'start' }}>
        <Label htmlFor={`${id}-code`}>Booking code</Label>

Error

Error: message from native validity

onInvalid turns the browser's validity flags into a specific message and suppresses the native bubble. The error is listed first in aria-describedby, before the permanent hint, and it is re-checked on input until it clears.

native-validity-message.tsx · 49 lines
import { Button, HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { FormEvent, useId, useState } from 'react';

const getMessage = (input: HTMLInputElement) => {
  if (input.validity.valueMissing) return 'Enter a postal code.';
  if (input.validity.patternMismatch) return 'Use 5 digits, for example 10115.';
  return '';
};

export default function NativeValidityMessage() {
  const id = useId();
  const [error, setError] = useState('');

Disabled

Disabled: explain why a field is locked

A disabled input cannot be focused, so the reason must be visible text rather than a tooltip. The hint says why the field is locked and links to the way out.

explain-disabled-field.tsx · 18 lines
import { HelperText, Label, Link, TextField, TextFieldInput } from '@vega-ui/react';
import { useId } from 'react';

export default function ExplainDisabledField() {
  const id = useId();

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%' }}>
      <Label htmlFor={id} style={{ color: 'var(--label-tertiary)' }}>Custom domain</Label>
      <TextField>
        <TextFieldInput id={id} placeholder='docs.northwind.io' disabled aria-describedby={`${id}-hint`} />
      </TextField>

Edge

Edge: long unbroken text in a narrow column

HelperText is inline-block, so a long URL would overflow a narrow column. overflowWrap: 'anywhere' lets it break at any character.

long-unbroken-hint.tsx · 18 lines
import { HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { useId } from 'react';

export default function LongUnbrokenHint() {
  const id = useId();

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%', maxWidth: 240 }}>
      <Label htmlFor={id}>Webhook URL</Label>
      <TextField>
        <TextFieldInput id={id} type='url' aria-describedby={`${id}-hint`} />
      </TextField>

Anatomy

Overview

HelperText is a single-part primitive. It renders a styled paragraph through the shared Text contract.

Required Parts

HelperText

Required. Owns helper-copy sizing and muted or error color.

Optional Parts

There are no exported child parts.

Composition Order

  1. HelperText
  2. short supporting copy

Valid Composition Patterns

field-hint.tsx · 17 lines
import { HelperText, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { useId } from 'react';

export default function FieldHint() {
  const id = useId();
  const hintId = `${id}-hint`;

  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-3)', width: '100%' }}>
      <Label htmlFor={id}>Recovery email</Label>
      <TextField>
        <TextFieldInput id={id} type='email' autoComplete='email' aria-describedby={hintId} />

Invalid Composition Patterns

Helper text used as the primary label

This weakens visible labeling and semantics.

Helper text used for full policy copy

The component is too lightweight for long-form explanatory content.