Loading Developer Playground

Loading ...

Skip to main content
ARIA ATTRIBUTEWidget Attributes

aria-placeholder

Defines a short hint intended to aid the user with data entry when the control has no value. Used for custom ARIA widgets where the native HTML placeholder attribute doesn't apply.

Value Type
string
Common Use
Custom Inputs
Compare To
HTML placeholder

Overview

The aria-placeholder attribute defines a short hint (a word or short phrase) intended to help users understand what data should be entered when a form control has no value.

This attribute is specifically for custom ARIA widgets like role="textbox" or role="combobox". For native HTML inputs, use the standard placeholder attribute instead.

Important Warning

Placeholders are NOT a replacement for labels! They disappear when users type, making the field unclear. Always use a visible <label> or aria-label in addition to placeholders.

Live Demo: Custom Search Input

Current value: (empty)

Screen reader announcement: When focused: "Search Products, combobox, collapsed, Type to search by name, SKU, or category..."

When to Use

✓ Use aria-placeholder

  • • Custom ARIA textbox widgets
  • • Custom combobox implementations
  • • Contenteditable elements with roles
  • • Rich text editors with ARIA roles
  • • Custom search inputs

✗ Don't Use aria-placeholder

  • • Native <input> elements (use placeholder)
  • • Native <textarea> elements (use placeholder)
  • • As a replacement for labels
  • • For essential instructions
  • • When label alone is sufficient

Code Examples

Basic Usage

<!-- Basic aria-placeholder usage -->

<!-- Custom combobox with placeholder -->
<div 
  role="combobox"
  aria-placeholder="Type to search..."
  aria-expanded="false"
  aria-haspopup="listbox"
  aria-labelledby="search-label"
  contenteditable="true"
  tabindex="0"
>
  <!-- Empty - shows placeholder -->
</div>

<!-- Custom textbox with placeholder -->
<div 
  role="textbox"
  aria-placeholder="Enter your message here"
  aria-multiline="true"
  contenteditable="true"
  tabindex="0"
>
</div>

<!-- Screen reader announcement: "Search, combobox, collapsed, Type to search..." -->

aria-placeholder vs placeholder

<!-- aria-placeholder vs HTML placeholder attribute -->

<!-- HTML placeholder (for native inputs) -->
<input 
  type="text" 
  placeholder="Enter your name"
  aria-label="Full name"
/>
<!--
  • Native browser support
  • Automatically announced by screen readers
  • Works only on <input> and <textarea>
  • No aria-placeholder needed!
-->

<!-- aria-placeholder (for custom widgets) -->
<div 
  role="textbox"
  aria-placeholder="Enter your name"
  aria-label="Full name"
  contenteditable="true"
  tabindex="0"
>
</div>
<!--
  • For ARIA widgets only
  • Provides placeholder hint to AT
  • Used with contenteditable elements
  • Required for custom input widgets
-->

<!-- WARNING: Don't use both together on native inputs -->
<input 
  type="text" 
  placeholder="Enter name"
  aria-placeholder="Enter name"  <!-- Redundant! -->
/>

Custom Search Input

<!-- Custom search combobox with placeholder -->
<div class="custom-search" role="search">
  <label id="search-label" for="search-input">Search Products</label>
  
  <div 
    id="search-input"
    role="combobox"
    aria-placeholder="Search by name, SKU, or category..."
    aria-expanded="false"
    aria-autocomplete="list"
    aria-haspopup="listbox"
    aria-controls="search-results"
    aria-labelledby="search-label"
    contenteditable="true"
    tabindex="0"
  ></div>
  
  <ul 
    id="search-results" 
    role="listbox" 
    aria-label="Search suggestions"
    hidden
  >
    <!-- Results populated dynamically -->
  </ul>
</div>

<style>
  /* Show placeholder when empty */
  [role="combobox"]:empty::before {
    content: attr(aria-placeholder);
    color: #9ca3af;
    pointer-events: none;
  }
</style>

Accessibility Considerations

<!-- Important: Placeholders are NOT labels! -->

<!-- BAD: Using placeholder as the only label -->
<div 
  role="textbox"
  aria-placeholder="Email address"  <!-- Not sufficient! -->
  contenteditable="true"
>
</div>

<!-- GOOD: Using proper label + placeholder -->
<label id="email-label">Email Address</label>
<div 
  role="textbox"
  aria-labelledby="email-label"
  aria-placeholder="name@example.com"
  aria-required="true"
  contenteditable="true"
>
</div>

<!-- Remember: -->
<!-- • Placeholders disappear when user types -->
<!-- • Some users don't see placeholders at all -->
<!-- • Labels are persistent and always visible -->
<!-- • Use placeholder for FORMAT hints, not instructions -->

React Component

// React Custom Textbox with aria-placeholder
import { useState, useRef, useEffect } from 'react';

function CustomTextbox({ 
  label, 
  placeholder, 
  onChange, 
  value,
  id,
  ...props 
}) {
  const textboxRef = useRef(null);
  const [isEmpty, setIsEmpty] = useState(!value);

  useEffect(() => {
    // Keep contenteditable in sync with value prop
    if (textboxRef.current && textboxRef.current.textContent !== value) {
      textboxRef.current.textContent = value || '';
    }
    setIsEmpty(!value);
  }, [value]);

  const handleInput = (e) => {
    const newValue = e.target.textContent;
    setIsEmpty(!newValue);
    onChange?.(newValue);
  };

  return (
    <div className="form-field">
      <label id={`${id}-label`} htmlFor={id}>
        {label}
      </label>
      <div
        ref={textboxRef}
        id={id}
        role="textbox"
        aria-labelledby={`${id}-label`}
        aria-placeholder={placeholder}
        contentEditable
        tabIndex={0}
        onInput={handleInput}
        className={`custom-textbox ${isEmpty ? 'empty' : ''}`}
        {...props}
      />
      <style>{`
        .custom-textbox {
          min-height: 40px;
          padding: 8px 12px;
          border: 1px solid #d1d5db;
          border-radius: 6px;
          outline: none;
        }
        .custom-textbox:focus {
          border-color: #6366f1;
          box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
        }
        .custom-textbox.empty::before {
          content: attr(aria-placeholder);
          color: #9ca3af;
          pointer-events: none;
        }
      `}</style>
    </div>
  );
}

// Usage
function SearchForm() {
  const [query, setQuery] = useState('');
  
  return (
    <CustomTextbox
      id="search"
      label="Search"
      placeholder="Type to search products..."
      value={query}
      onChange={setQuery}
    />
  );
}

Best Practices

Always provide a visible label in addition to aria-placeholder

Use placeholder for format hints (e.g., "mm/dd/yyyy") not instructions

Keep placeholder text short and helpful

Use CSS to visually display placeholder when content is empty

Ensure sufficient color contrast for placeholder text

×

Don't use placeholder as the only label—it disappears when typing

×

Don't put essential information only in placeholder text

×

Don't use on native inputs—use HTML placeholder attribute instead

×

Don't make placeholder text too long—keep it concise

Common Use Cases

Custom ARIA combobox widgets
Rich text editors
Custom search inputs
Contenteditable fields
Custom date pickers
Format hint examples
Custom autocomplete fields
WYSIWYG editor placeholders

Related Attributes

Specifications & Resources