Logo Upload
A compound component for uploading logos or profile images. Shows a rounded avatar preview with placeholder, title, description, and action buttons. Designed to work with the useFileUpload hook.
Installation
bunx @happlyui/cli@latest add logo-upload
Dependencies
Registry dependencies
These are automatically installed when you add this component.
avatarbuttonloadertvhapply-ui-utilsuse-file-upload
Usage
import * as LogoUpload from "@/components/ui/logo-upload"
import * as Button from "@/components/ui/button"
import { useFileUpload } from "@/hooks/use-file-upload"
const upload = useFileUpload({ ... })
const file = upload.files[0]
<LogoUpload.Root>
<LogoUpload.Preview file={file} placeholderType="company" />
<LogoUpload.Content>
<LogoUpload.Title>Business logo</LogoUpload.Title>
<LogoUpload.Description>
<p>Supports JPEG or PNG files (max 3MB).</p>
</LogoUpload.Description>
<LogoUpload.Actions>
<Button.Root variant="neutral" mode="stroke" size="xsmall" onClick={upload.openFilePicker}>
Change
</Button.Root>
<input {...upload.getInputProps()} />
</LogoUpload.Actions>
</LogoUpload.Content>
</LogoUpload.Root>
Examples
Default (Empty State)
Shows a company placeholder avatar when no file has been uploaded yet.
Business logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
<LogoUpload.Root>
<LogoUpload.Preview placeholderType="company" />
<LogoUpload.Content>
<LogoUpload.Title>Business logo</LogoUpload.Title>
<LogoUpload.Description>
<p>Supports JPEG or PNG files (max 3MB).</p>
<p>Use a horizontal image (16:9). Best size: 1200 × 675 px.</p>
</LogoUpload.Description>
<LogoUpload.Actions>
<Button.Root variant="neutral" mode="stroke" size="xsmall">Change</Button.Root>
</LogoUpload.Actions>
</LogoUpload.Content>
</LogoUpload.Root>
With Uploaded Logo
Shows the uploaded image in the avatar preview.
Business logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
<LogoUpload.Root>
<LogoUpload.Preview file={file} />
<LogoUpload.Content>
<LogoUpload.Title>Business logo</LogoUpload.Title>
<LogoUpload.Description>
<p>Supports JPEG or PNG files (max 3MB).</p>
</LogoUpload.Description>
<LogoUpload.Actions>
<Button.Root variant="neutral" mode="stroke" size="xsmall">Change</Button.Root>
</LogoUpload.Actions>
</LogoUpload.Content>
</LogoUpload.Root>
Uploading
While a file is uploading, the preview shows a spinner overlay. When a preview image is available, the image blurs behind the spinner.
Business logo
Uploading new-logo.png… 45%
Business logo
Uploading new-logo.png… 45%
<LogoUpload.Root>
<LogoUpload.Preview file={uploadingFile} />
<LogoUpload.Content>
<LogoUpload.Title>Business logo</LogoUpload.Title>
<LogoUpload.Description>
<p>Uploading new-logo.png… 45%</p>
</LogoUpload.Description>
</LogoUpload.Content>
</LogoUpload.Root>
Custom Preview
Replace LogoUpload.Preview with any custom element. Since Root is a flex container, drop in your own preview markup.
Business logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
<LogoUpload.Root>
<LogoUpload.Preview
placeholder={<RiBuildingLine className="size-[60px] text-[#B8ACF6]" />}
avatarClassName="bg-[#EFEBFF] ring-[1.26px] ring-[rgba(14,18,27,0.1)]"
/>
<LogoUpload.Content>
<LogoUpload.Title>Business logo</LogoUpload.Title>
<LogoUpload.Description>
<p>Supports JPEG or PNG files (max 3MB).</p>
</LogoUpload.Description>
<LogoUpload.Actions>
<Button.Root variant="neutral" mode="stroke" size="xsmall">Change</Button.Root>
</LogoUpload.Actions>
</LogoUpload.Content>
</LogoUpload.Root>
User Avatar Upload
Use placeholderType="user" for profile photo uploads.
Profile photo
Supports JPEG or PNG files (max 3MB).
Use a square image. Best size: 400 × 400 px.
<LogoUpload.Root>
<LogoUpload.Preview placeholderType="user" />
<LogoUpload.Content>
<LogoUpload.Title>Profile photo</LogoUpload.Title>
<LogoUpload.Description>
<p>Supports JPEG or PNG files (max 3MB).</p>
</LogoUpload.Description>
<LogoUpload.Actions>
<Button.Root variant="neutral" mode="stroke" size="xsmall">Change</Button.Root>
</LogoUpload.Actions>
</LogoUpload.Content>
</LogoUpload.Root>
Composed
Use LogoUpload.Item for a single-prop composed version that handles the full layout.
Business logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
<LogoUpload.Item
label="Business logo"
description={
<>
<p>Supports JPEG or PNG files (max 3MB).</p>
<p>Use a horizontal image (16:9). Best size: 1200 × 675 px.</p>
</>
}
onButtonClick={upload.openFilePicker}
/>
Composed with Logo
The composed version showing an uploaded image.
Business logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
<LogoUpload.Item
file={upload.files[0]}
label="Business logo"
description={<p>Supports JPEG or PNG files (max 3MB).</p>}
onButtonClick={upload.openFilePicker}
/>
With FormField
Wrap LogoUpload.Item inside FormField.Root for label, hint, and error support.
Upload a logo
Supports JPEG or PNG files (max 3MB).
Use a horizontal image (16:9). Best size: 1200 × 675 px.
Upload a logo
Supports JPEG or PNG files (max 3MB).
<FormField.Root label="Business logo" hint="Used on your public profile and invoices.">
<LogoUpload.Item
label="Upload a logo"
description={<p>Supports JPEG or PNG files (max 3MB).</p>}
onButtonClick={upload.openFilePicker}
/>
</FormField.Root>
API Reference
LogoUpload.Root
The outer container with border and padding.
| Prop | Type | Default | Description |
|---|
LogoUpload.Preview
Renders a rounded avatar showing the uploaded image or a placeholder icon.
| Prop | Type | Default | Description |
|---|---|---|---|
file | UploadFile | - | The file state from useFileUpload. Shows preview/url when available, otherwise shows placeholder. |
placeholderType | 'user' | 'company' | 'company' | The placeholder icon type when no image is available. |
avatarColor | 'gray' | 'yellow' | 'blue' | 'sky' | 'purple' | 'red' | 'primary' | 'gray' | The background color of the placeholder avatar. |
LogoUpload.Content
Wraps the title, description, and actions.
| Prop | Type | Default | Description |
|---|
LogoUpload.Title
The heading text (e.g. "Business logo").
| Prop | Type | Default | Description |
|---|
LogoUpload.Description
Container for description paragraphs (file requirements, size hints).
| Prop | Type | Default | Description |
|---|
LogoUpload.Actions
Container for action buttons (Change, Retry, etc.).
| Prop | Type | Default | Description |
|---|
LogoUpload.Item
Composed preset that renders the full logo upload layout from props.
| Prop | Type | Default | Description |
|---|---|---|---|
file | UploadFile | - | The file state from useFileUpload. Shows uploaded image when available. |
label | string | - | The title text (e.g. "Business logo"). |
description | ReactNode | - | Description content rendered below the title. |
placeholderType | 'user' | 'company' | 'company' | The placeholder icon type when no image is available. |
avatarColor | 'gray' | 'yellow' | 'blue' | 'sky' | 'purple' | 'red' | 'primary' | 'gray' | The background color of the placeholder avatar. |
buttonLabel | string | 'Change' | Label for the action button. |
onButtonClick | () => void | - | Click handler for the action button (typically upload.openFilePicker). |