shadcn.io is not affiliated with official shadcn/ui
Import and Export Task List Block for Ark UI
A task list with an Import / export dialog shown open: paste Markdown or CSV lines and see a live count before importing, or export the list as Markdown, CSV, JSON or text with Copy and a real Download.
Installation
Overview
Let people move their tasks in and out, with this import and export dialog for React with Ark UI. It sits on the task list of Ferrylist, a move-your-tasks tool: the page's header holds an outline Import / export Button, and the list is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog has two Tabs. Import holds a Textarea for pasted lines (Markdown checkboxes, bullets, numbered or plain lines, or a CSV with a title,done,due header) and a live summary such as "4 tasks, 1 done, 1 blank line skipped". Export holds a Segment Group of Markdown, CSV, JSON and Text over a preview of the file, with a Copy button. The only Shine Button reads "Import 4 tasks" on the first tab and "Download .md" on the second, and the download is a real file made in the browser. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog. For task apps, migrations and backups.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the list: a native dialog element that isn't modal, so nothing is trapped, hidden or focused. The Import / export button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same PortFields component and share the block's state, so text pasted in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
What does the importer accept?
parseImport reads one task per line. - [x] Pay the water bill and - [ ] Order paint set the done flag, bullets and numbered lines (1., 2)) give the title, and a plain line is a title. If the first line starts with title, the paste is read as CSV and the columns title, done and due are found by name. Blank lines are skipped and counted in the summary, and Import is refused, with a message under the field, when nothing is found.
Is the download a real file?
Yes. Download builds a Blob of exactly the preview text, with the format's media type, gives it a name like ferrylist-tasks.md and clicks a temporary link; the browser saves it and nothing is uploaded. Copy uses the clipboard API and says whether the browser allowed it.
What stays local, and how do I save for real?
The list is local state: imported tasks go to the top and it resets on reload. In your app send the parsed drafts from importNow to your API (and show its errors under the field), and build the export from your stored tasks, or fetch it from the server for large lists.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus starts inside and stays there until it closes, and Escape, Cancel and the close button return focus to the header button. The trigger is the button wrapped in DialogTrigger with asChild, and the dialog is controlled with open and onOpenChange. The tabs, the format choice and the preview (a named, focusable scroll region) all work with the arrow keys and Tab.