Hooks/Utilities/useDocumentTitle

useDocumentTitle

A custom React hook that sets the document title with React.useLayoutEffect.

useDocumentTitle is a custom React hook that sets the document title using useLayoutEffect for synchronous updates. It's designed for client-only applications and will not run during server-side rendering. The hook provides options for restoring the original title when the component unmounts, making it perfect for dynamic title management.

Example

Loading...

Install

npx shadcn@latest add https://unlogg.com/r/use-document-title.json
pnpm dlx shadcn@latest add https://unlogg.com/r/use-document-title.json
bunx shadcn@latest add https://unlogg.com/r/use-document-title.json

Notes

  • Uses useLayoutEffect for synchronous DOM updates before paint
  • Only runs on client-side (safe for SSR applications)
  • Supports optional title restoration on component unmount
  • Accepts null/undefined to skip title updates
  • Stores original title for restoration purposes
  • Ideal for client-only applications and dynamic title updates

API Reference

Parameters

PropTypeDefault
options?
object
{}
title?
string | null | undefined

Options

PropTypeDefault
restoreOnUnmount?
boolean
false

Returns

PropTypeDefault
void?
void
-

Usage

import { useDocumentTitle } from "@/hooks/use-document-title";

function MyPage() {
  useDocumentTitle("My Page Title");
  
  return <div>Page content</div>;
}

Advanced Usage

Dynamic Title Updates

Update the title based on component state:

function DynamicPage() {
  const [count, setCount] = useState(0);
  const [user, setUser] = useState(null);
  
  // Dynamic title based on state
  useDocumentTitle(
    user ? `${user.name}'s Dashboard (${count} items)` : `Dashboard (${count} items)`
  );
  
  return (
    <div>
      <h1>Dashboard</h1>
      <p>Items: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>
        Add Item
      </button>
    </div>
  );
}

Conditional Title Setting

Set title only when certain conditions are met:

function ConditionalTitle() {
  const [isImportant, setIsImportant] = useState(false);
  const [notification, setNotification] = useState(null);
  
  // Only set title when there's an important notification
  useDocumentTitle(
    isImportant && notification ? `🔔 ${notification}` : null
  );
  
  return (
    <div>
      <button onClick={() => setIsImportant(!isImportant)}>
        {isImportant ? "Mark Normal" : "Mark Important"}
      </button>
      <input 
        value={notification || ""}
        onChange={(e) => setNotification(e.target.value)}
        placeholder="Enter notification..."
      />
    </div>
  );
}

Restore Original Title

Use the restoreOnUnmount option for temporary title changes:

function TemporaryModal({ isOpen, onClose }) {
  // This will restore the original title when modal closes
  useDocumentTitle(
    isOpen ? "🎯 Important: Review Required" : null,
    { restoreOnUnmount: true }
  );
  
  if (!isOpen) return null;
  
  return (
    <div className="modal">
      <h2>Important Action Required</h2>
      <p>Please review the following...</p>
      <button onClick={onClose}>Close</button>
    </div>
  );
}

Create breadcrumb-style titles for navigation:

function ProductPage({ category, product }) {
  const title = useMemo(() => {
    const parts = ["MyStore"];
    if (category) parts.push(category.name);
    if (product) parts.push(product.name);
    return parts.join(" > ");
  }, [category, product]);
  
  useDocumentTitle(title);
  
  return (
    <div>
      <nav>
        <Link to="/">Home</Link>
        {category && (
          <>
            <span> > </span>
            <Link to={`/category/${category.id}`}>{category.name}</Link>
          </>
        )}
        {product && (
          <>
            <span> > </span>
            <span>{product.name}</span>
          </>
        )}
      </nav>
      {/* Product content */}
    </div>
  );
}

Real-time Updates

Update title with live data:

function LiveCounter() {
  const [count, setCount] = useState(0);
  const [isActive, setIsActive] = useState(false);
  
  // Update title with current count when active
  useDocumentTitle(isActive ? `Live Count: ${count}` : null);
  
  useEffect(() => {
    if (!isActive) return;
    
    const interval = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(interval);
  }, [isActive]);
  
  return (
    <div>
      <h1>Counter: {count}</h1>
      <button onClick={() => setIsActive(!isActive)}>
        {isActive ? "Stop" : "Start"} Live Title
      </button>
    </div>
  );
}

Form with Validation Status

Show form status in the title:

function ContactForm() {
  const [formData, setFormData] = useState({ name: "", email: "" });
  const [errors, setErrors] = useState({});
  const [isDirty, setIsDirty] = useState(false);
  
  const isValid = Object.keys(errors).length === 0;
  const titleSuffix = isDirty ? (isValid ? " ✓" : " ⚠️") : "";
  
  useDocumentTitle(`Contact Form${titleSuffix}`);
  
  const handleChange = (field, value) => {
    setFormData(prev => ({ ...prev, [field]: value }));
    setIsDirty(true);
    // Validation logic here...
  };
  
  return (
    <form>
      <input 
        value={formData.name}
        onChange={(e) => handleChange("name", e.target.value)}
        placeholder="Name"
      />
      <input 
        value={formData.email}
        onChange={(e) => handleChange("email", e.target.value)}
        placeholder="Email"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Use Cases

  • Page Identification: Set descriptive titles for different pages and views
  • Dynamic Content: Update titles based on loaded data or user actions
  • Notification System: Show urgent information in the browser tab
  • Form Management: Indicate form status or validation state
  • Real-time Updates: Display live data like unread messages or timer counts
  • Modal Dialogs: Temporarily change title when important dialogs are open
  • Navigation Context: Show current location in multi-level navigation
  • Progress Tracking: Display progress status for long-running operations