Pro--% off in--d : --h : --m : --s
HeroUI

Alert

Migration guide for Alert from HeroUI v2 to v3

Refer to the v3 Alert documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.

Structure Changes

In v2, Alert was a single component that accepted props for title, description, icon, and other elements:

import { Alert } from "@heroui/react";

export default function App() {
  return (
    <Alert 
      title="This is an alert"
      description="Thanks for subscribing to our newsletter!"
    />
  );
}

In v3, Alert uses a compound component pattern with explicit subcomponents:

import { Alert } from "@heroui/react";

export default function App() {
  return (
    <Alert>
      <Alert.Indicator />
      <Alert.Content>
        <Alert.Title>This is an alert</Alert.Title>
        <Alert.Description>
          Thanks for subscribing to our newsletter!
        </Alert.Description>
      </Alert.Content>
    </Alert>
  );
}

Key Changes

1. Component Structure

v2: Single Alert component with props
v3: Compound components: Alert, Alert.Indicator, Alert.Content, Alert.Title, Alert.Description

2. Color/Status Props

v2 Colorv3 StatusNotes
defaultdefaultSame
primaryaccentRenamed
secondarydefaultUse default status
successsuccessSame
warningwarningSame
dangerdangerSame

3. Variants Removed

v2 Variants: solid, bordered, flat, faded
v3: No variant prop - use Tailwind CSS classes to achieve similar effects

To achieve v2 variant styles in v3:

  • v2 solid → v3 status + add background color classes
  • v2 bordered → v3 status + add border classes
  • v2 flat → v3 default (no additional classes needed)
  • v2 faded → v3 status + add opacity/background classes

4. Prop Changes

v2 Propv3 LocationNotes
variant-Removed (use Tailwind CSS)
radius-Removed (use Tailwind e.g. rounded-lg)
startContent-Place content before <Alert.Indicator />
endContent-Place content after <Alert.Content />
hideIcon-Omit <Alert.Indicator />
hideIconWrapper-Removed (no wrapper in v3)
iconAlert.IndicatorRender icon as child of <Alert.Indicator />
isVisible, isDefaultVisible, onVisibleChange-Removed (handle with conditional rendering)
isClosable, onClose, closeButtonProps-Removed (add CloseButton manually)
titleAlert.TitleUse <Alert.Title> inside <Alert.Content>
descriptionAlert.DescriptionUse <Alert.Description> inside <Alert.Content>

5. Icon Handling

v2: Used icon prop or hideIcon prop
v3: Use <Alert.Indicator /> with custom children or omit it entirely

Migration Examples

Icon Handling

import { Icon } from '@iconify/react';

{/* With custom icon */}
<Alert 
  icon={<Icon icon="gravity-ui:box" />}
  title="Custom Icon Alert"
/>

{/* Without icon */}
<Alert hideIcon title="No Icon Alert" />
import { Icon } from '@iconify/react';

{/* With custom icon */}
<Alert>
  <Alert.Indicator>
    <Icon icon="gravity-ui:box" />
  </Alert.Indicator>
  <Alert.Content>
    <Alert.Title>Custom Icon Alert</Alert.Title>
  </Alert.Content>
</Alert>

{/* Without icon */}
<Alert>
  <Alert.Content>
    <Alert.Title>No Icon Alert</Alert.Title>
  </Alert.Content>
</Alert>

With Action Button (End Content)

import { Alert, Button } from "@heroui/react";

<Alert
  title="You have no credits left"
  description="Upgrade to a paid plan to continue"
  endContent={
    <Button color="warning" size="sm" variant="flat">
      Upgrade
    </Button>
  }
/>
import { Alert, Button } from "@heroui/react";

<Alert status="warning">
  <Alert.Indicator />
  <Alert.Content>
    <Alert.Title>You have no credits left</Alert.Title>
    <Alert.Description>
      Upgrade to a paid plan to continue
    </Alert.Description>
    <Button className="mt-2" size="sm" variant="primary">
      Upgrade
    </Button>
  </Alert.Content>
</Alert>

Closable Alert

<Alert
  title="Closable Alert"
  isClosable
  onClose={() => console.log("Closed")}
/>
import { Alert, CloseButton } from "@heroui/react";
import { useState } from "react";

const [isVisible, setIsVisible] = useState(true);

{isVisible && (
  <Alert>
    <Alert.Indicator />
    <Alert.Content>
      <Alert.Title>Closable Alert</Alert.Title>
    </Alert.Content>
    <CloseButton 
      aria-label="Close"
      onPress={() => setIsVisible(false)}
    />
  </Alert>
)}

Styling Changes

v2: classNames Prop

<Alert 
  classNames={{
    base: "custom-base",
    title: "custom-title",
    description: "custom-description"
  }}
/>

v3: Direct className Props

<Alert className="custom-base">
  <Alert.Indicator />
  <Alert.Content>
    <Alert.Title className="custom-title">Title</Alert.Title>
    <Alert.Description className="custom-description">
      Description
    </Alert.Description>
  </Alert.Content>
</Alert>

Component Anatomy

The v3 Alert follows this structure:

Alert (Root)
  ├── Alert.Indicator (optional)
  ├── Alert.Content (optional)
  │   ├── Alert.Title (optional)
  │   └── Alert.Description (optional)
  └── [Additional content like buttons, close button, etc.] (optional)

Summary

  1. Component Structure: Must use compound components instead of props
  2. Color → Status: color prop renamed to status, primaryaccent, secondarydefault
  3. Variants Removed: No variant prop; use Tailwind CSS classes
  4. Radius Removed: No radius prop; use Tailwind CSS classes
  5. No Built-in Close Button: Must add CloseButton manually
  6. No Visibility Control: Handle visibility with conditional rendering
  7. No Start/End Content Props: Place content directly in the component tree
  8. Icon Handling: Use <Alert.Indicator /> with children or omit it

On this page