# Pixel upload
> Upload drop zone where the file icon dissolves pixel by pixel into the progress bar, which regroups into a check; oversized files shake red.
- Element: `<px-upload>`
- React: `import { PxUpload } from "@/components/lumesec/px-upload"`
- Collection: Pixel Lab (https://elements.lumesec.ai/components/pixel-lab)
- Registry item: https://elements.lumesec.ai/r/px-upload.json
- Page: https://elements.lumesec.ai/components/pixel-lab/upload



Live preview: https://elements.lumesec.ai/view/px-upload

```html
<script type="module" src="https://elements.lumesec.ai/cdn/px-upload.js"></script>

<px-upload></px-upload>
```

## Playground

Change a prop and the component updates. Props marked live animate to the new value; the others rebuild the element.

## Installation

```bash
npx shadcn@latest add @lumesec/px-upload
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/px-upload.json
```

## Usage

React:

```tsx
import { PxUpload } from "@/components/lumesec/px-upload";

export function Example() {
  return (
    <PxUpload />
  );
}
```

HTML:

```html
<script type="module" src="https://elements.lumesec.ai/cdn/px-upload.js"></script>

<px-upload></px-upload>
```

## Behaviour

The file icon dissolves from its corner, and each pixel arcs down into the progress bar. When it fills, the bar regroups into a check; files over the limit turn red and shake. Real files work too.

## API reference

### Attributes

| Attribute  | React prop | Type     | Default | Description                                                                         |
| ---------- | ---------- | -------- | ------- | ----------------------------------------------------------------------------------- |
| `limit-mb` | `limitMb`  | `number` | `30`    | Size limit in megabytes (1 MB = 1,000,000 bytes). Read each time a file is started. |

### Events

Events bubble and cross the shadow boundary unless the description says otherwise.

| Event      | React prop   | Detail                           | Description                                                    |
| ---------- | ------------ | -------------------------------- | -------------------------------------------------------------- |
| `error`    | `onError`    | `{ name: string, size: number }` | Fires when a file is over the limit. `size` is in bytes.       |
| `uploaded` | `onUploaded` | `{ name: string, size: number }` | Fires when the simulated upload completes. `size` is in bytes. |

### Methods

Call them on the element, for example through a React ref.

| Method                              | Description                                                                                 |
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
| `start(name: string, size: number)` | Runs the upload animation for a file of `size` bytes. Ignored unless the component is idle. |
| `reset()`                           | Returns to the idle drop zone.                                                              |

### Properties

| Property            | Type     | Description                               |
| ------------------- | -------- | ----------------------------------------- |
| `limit` (read-only) | `number` | The size limit in bytes, from `limit-mb`. |

## Keyboard

| Keys                             | Action                           |
| -------------------------------- | -------------------------------- |
| Enter / Space (on the drop zone) | Open the file picker while idle. |

## Accessibility

* The drop zone is focusable with `role="button"` and `aria-label="Upload a file: click or drop"`.
* The status line ("Uploading …", "Uploaded", "Over the 30 MB limit") is an `aria-live="polite"` region.
* "Use a sample file" and "Try a 48 MB file" are native buttons.
* Reduced motion: the icon does not bob, the border does not march, an error does not shake and pixels jump to the bar and the check instead of arcing.

## Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--destructive`, `--foreground`, `--lumesec`, `--lumesec-success` and `--muted-foreground`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-danger`, `--ui-fg`, `--ui-mono`, `--ui-muted` and `--ui-ok`.

## Notes

* Nothing is sent over the network. A chosen or dropped file is used only for its name and size, and progress is simulated over 1.6 to 3.4 seconds depending on size.
* The two demo buttons start a 2.4 MB sample and a 48.2 MB file that exceeds the default limit. Only the first file of a drop is used.
* The host carries `data-state="uploading"`, `"error"` or `"done"`, and returns to idle 2.6 seconds after an error and 2.8 seconds after success.
* The drop zone is 178px tall.


