Loading Developer Playground

Loading ...

Skip to main content
ARIA ROLELive Region Roles

log

A type of live region where new information is added in meaningful order and old information may disappear. Perfect for chat applications, activity feeds, and sequential data streams.

Implicit aria-live
polite
Implicit aria-atomic
false
Required Attributes
None

Overview

The log role is used for sequential information where new items are added in a meaningful order. Unlike other live regions, logs typically only announce new additions, not the entire history.

With aria-atomic="false" by default, screen readers announce only the newly added content, making it ideal for chat applications, activity feeds, and system logs.

Live Demo: Activity Log

Welcome to the chat!

Note: Only new entries are announced to screen readers, not the entire log. This prevents overwhelming users with redundant information.

Code Examples

Basic Log

<!-- Basic Log (Chat/Activity Feed) -->
<div role="log" aria-label="Chat Messages">
  <div class="message">Alice: Hello!</div>
  <div class="message">Bob: Hi there!</div>
  <!-- New messages will be announced as they're added -->
</div>

<!-- Implicit aria-live="polite" and aria-atomic="false" -->

Chat Application

<!-- Chat Application -->
<div id="chat-log" 
     role="log" 
     aria-label="Chat conversation"
     aria-atomic="false">
  <!-- Messages are added here -->
</div>

<script>
  function addChatMessage(user, text) {
    const log = document.getElementById('chat-log');
    const message = document.createElement('div');
    message.className = 'chat-message';
    message.innerHTML = `
      <strong>${user}:</strong>
      <span>${text}</span>
      <time>${new Date().toLocaleTimeString()}</time>
    `;
    
    log.appendChild(message);
    
    // Screen reader announces: "Alice: Hello everyone!"
    // (only the new message, not the entire chat history)
    
    // Auto-scroll to latest
    log.scrollTop = log.scrollHeight;
  }
</script>

Activity Log

<!-- Activity/Audit Log -->
<div id="activity-log" 
     role="log" 
     aria-label="Recent Activity"
     class="log-container">
  <div class="log-entry">
    <time>10:30 AM</time>
    <span>User login successful</span>
  </div>
  <div class="log-entry">
    <time>10:31 AM</time>
    <span>File uploaded: report.pdf</span>
  </div>
</div>

<script>
  function logActivity(action) {
    const log = document.getElementById('activity-log');
    const entry = document.createElement('div');
    entry.className = 'log-entry';
    entry.innerHTML = `
      <time>${new Date().toLocaleTimeString()}</time>
      <span>${action}</span>
    `;
    
    log.appendChild(entry);
    
    // Keep only last 50 entries
    while (log.children.length > 50) {
      log.removeChild(log.firstChild);
    }
  }
</script>

React Component

// React Log Component
import { useState, useRef, useEffect } from 'react';

function ChatLog({ messages }) {
  const logRef = useRef(null);
  
  // Auto-scroll to bottom when new message
  useEffect(() => {
    if (logRef.current) {
      logRef.current.scrollTop = logRef.current.scrollHeight;
    }
  }, [messages]);
  
  return (
    <div
      ref={logRef}
      role="log"
      aria-label="Chat Messages"
      aria-atomic="false"
      className="chat-log"
    >
      {messages.map((msg, index) => (
        <div key={index} className="message">
          <strong>{msg.user}:</strong>
          <span>{msg.text}</span>
          <time>{msg.timestamp}</time>
        </div>
      ))}
    </div>
  );
}

// Activity Log Example
function ActivityLog() {
  const [activities, setActivities] = useState([]);
  
  const addActivity = (action) => {
    const newActivity = {
      id: Date.now(),
      action,
      timestamp: new Date().toISOString(),
    };
    
    setActivities(prev => {
      // Keep only last 100 entries
      const updated = [...prev, newActivity];
      return updated.slice(-100);
    });
  };
  
  return (
    <div
      role="log"
      aria-label="Activity Feed"
      className="activity-log"
    >
      {activities.map(activity => (
        <div key={activity.id} className="activity">
          <time>{new Date(activity.timestamp).toLocaleTimeString()}</time>
          <span>{activity.action}</span>
        </div>
      ))}
    </div>
  );
}

Best Practices

Use for chat messages and conversations

Use for activity feeds and history logs

Use for console output and debug messages

Provide aria-label to identify the log

Limit log size - remove old entries to improve performance

Auto-scroll to show newest entries

×

Don't use for critical alerts - use role="alert" instead

×

Don't let logs grow infinitely - implement cleanup

×

Don't use for static, unchanging lists

Related Roles

Specifications & Resources