Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Annotation File Upload Block for Svelte

Numbered pins on a drawn checkout screen: click or press Enter to drop a pin, nudge it with the arrow keys, write its note in the list, delete to renumber, and copy the pins as JSON.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Pin a note to the exact spot, with this annotation panel for Svelte with Ark UI. It is the review board of Calloutly, a design-review tool. A drawn checkout screen sits at the start of a framed panel; click it, or focus it and press Enter, and a numbered pin drops there, or press Add pin at centre, the one Shine Button. Each pin is a 44 px target: select it and the arrow keys nudge it (Shift for bigger steps), and Delete removes it. At the end a list holds one note per pin in a Textarea; focusing a note selects its pin, and removing a pin renumbers the rest. A count shows pins out of eight, an Empty state holds the list's height when it is clear, and Copy JSON puts the pins and notes on the clipboard. A File Upload trigger names a picked screenshot while the drawing stays. The panel is ruled by Guides. For design review, QA and any markup of an image.

FAQ

How do I add and move a pin?

Click or tap the screen to drop one where you pointed, or press Enter on the focused screen or the Add button to drop one at the centre. A new pin is selected and its note takes focus. With a pin focused, the arrow keys move it by 2 percent of the screen, or 10 with Shift, and it stays inside the picture.

What happens when I delete a pin?

The pin goes, the rest are renumbered in order, and focus moves to the next note (or the one before it, or the Add button when none is left). The status line says which pin was removed. Eight pins is the most; the Add button then says so and adds nothing.

What is in the copied JSON?

The screenshot's name and the pins in order, each with its number, its x and y as percentages of the screen and its note. Coordinates are relative, so they hold at any display size.

What happens when I choose a screenshot?

Its name appears in the caption and the status line, and the drawing stays: the block never reads a picked file, so pins land on the drawn screen. A file that is not an image is refused with a line in the status.

What stays local in the demo, and how do I wire it up?

Pins and notes live in this tab and are lost on reload. In your app load the real image into the canvas, keep the same percentage coordinates, save the pins with your review record, and sync them to teammates from your server.

Is it accessible without a pointer?

Yes. The screen is a button, each pin is a button named with its number and position, and the arrow keys, Delete and the note fields cover moving, removing and writing. Every pin is 44 by 44 px, and the status line announces each change.