CSV Import Kit

v0.1.1

Generic modal shell and building blocks for a CSV bulk-import flow: drop zone, review-mode toggles, banners, success state, and a labeled select for review-row fields.

View as Markdown

Install

npx shadcn@4.1.2 add @signalos/csv-import-kit

Requires a configured @signalos registry and a valid SIGNALOS_REGISTRY_TOKEN - get access. Registry dependencies (@signalos/tokens, @signalos/utils, @signalos/button, @signalos/switch, @signalos/select, @signalos/confirm-dialog) are pulled automatically.

Preview

Example & code

csv-import-kit.example.tsx
// Example: a minimal CSV import flow - upload, then a success state.
import { useState } from "react"

import { CsvImportKitDropZone } from "@/components/widgets/csv-import-kit/components/CsvImportKitDropZone"
import { CsvImportKitSuccessState } from "@/components/widgets/csv-import-kit/components/CsvImportKitSuccessState"
import { CsvImportKit } from "@/components/widgets/csv-import-kit/CsvImportKit"

export default function Example() {
  const [open, setOpen] = useState(true)
  const [file, setFile] = useState<File | null>(null)

  return (
    <CsvImportKit
      open={open}
      onClose={() => setOpen(false)}
      title="Import Users"
      description="Add multiple users from a CSV file."
    >
      {file ? (
        <CsvImportKitSuccessState
          title="Import completed successfully"
          description={`${file.name} was imported successfully.`}
          onReset={() => setFile(null)}
        />
      ) : (
        <CsvImportKitDropZone
          isProcessing={false}
          hint="Required: full_name, email, role"
          onFile={setFile}
        />
      )}
    </CsvImportKit>
  )
}

Props

CsvImportKitProps

PropTypeDefaultDescription
open*boolean-Whether the modal is open. Renders nothing when `false`.
onClose*() => void-Fired to request the modal close immediately (no dirty-close guard).
title*ReactNode-Modal title, e.g. "Import Users".
descriptionReactNode-Modal subtitle shown under the title.
isWideboolean | undefinedfalseWidens the modal for wide content such as a review grid.
isSubmittingboolean | undefinedfalseDisables the close/expand controls while a submission is in flight.
isDirtyboolean | undefinedfalseWhen `true`, closing the modal first asks the user to confirm via the built-in discard-changes dialog instead of closing immediately.
discardTitlestring | undefined"Discard unsaved changes?"
discardDescriptionReactNode"Your changes will be lost."
discardConfirmLabelReactNode"Discard changes"
discardCancelLabelReactNode"Keep editing"
childrenReactNode-Step content rendered in the scrollable body.
footerReactNode-Sticky footer content, e.g. `CsvImportKitFooter`. Omit to render no footer.
classNamestring | undefined-Extra classes merged onto the root overlay element.
data-testidstring | undefined-Test identifier rendered as `data-testid` on the dialog element.

CsvImportKitDropZoneProps

PropTypeDefaultDescription
titlestring | undefined"Upload your CSV file"
descriptionstring | undefined"Drag and drop or browse from your computer"
hintstring | undefined-Short hint about required/optional columns, shown under the drop area.
isProcessing*boolean-Disables the drop zone and shows a processing indicator.
onFile*(file: File) => void-Fired with the dropped or browsed file once its extension passes the `.csv` check.
onInvalidFile((reason: string) => void) | undefined-Fired instead of `onFile` when the selected file fails the `.csv` extension check.
onDownloadTemplate(() => void) | undefined-Renders a "Download template" action when provided.
formatNote{ title: string; description: ReactNode; } | undefined-Expands the template action into a labeled note above the drop zone.
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitSelectedFileProps

PropTypeDefaultDescription
file*File-The selected file, used for its name only.
onRemove*() => void-Fired when the remove action is activated.
fileTypeLabelstring | undefined"CSV file"Label shown under the file name.
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitBannerProps

PropTypeDefaultDescription
message*ReactNode-Body message.
onDismiss*() => void-Fired when the dismiss action is activated.
toneCsvImportKitBannerTone | undefined"error"
titleReactNode-Overrides the tone's default heading.
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitSuccessStat

PropTypeDefaultDescription
label*string-
value*number-

CsvImportKitSuccessStateProps

PropTypeDefaultDescription
title*ReactNode-
descriptionReactNode-
onReset*() => void-Fired when the reset action is activated.
resetLabelReactNode"Upload another file"
statsCsvImportKitSuccessStat[] | undefined-Optional stat tiles summarizing the completed import.
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitFooterProps

PropTypeDefaultDescription
onCancel*() => void-Fired when the cancel action is activated.
onSubmit*() => void-Fired when the submit action is activated.
isSubmitting*boolean-Disables cancel and shows a spinner + `submittingLabel` on submit.
disabled*boolean-Disables the submit action independent of `isSubmitting`.
submitLabel*ReactNode-Submit action label when idle.
cancelLabelReactNode"Cancel"
submittingLabelReactNode"Importing..."Submit action label while `isSubmitting`.
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitModeOption

PropTypeDefaultDescription
value*CsvImportKitReviewMode-
title*ReactNode-
description*ReactNode-

CsvImportKitModeToggleProps

PropTypeDefaultDescription
mode*CsvImportKitReviewMode-
onChange*(mode: CsvImportKitReviewMode) => void-
options*[CsvImportKitModeOption, CsvImportKitModeOption]-The two options rendered, in order. The caller composes their own copy (e.g. counts of invalid/existing rows) rather than the toggle knowing about review-row shapes.
ariaLabelstring | undefined"How to handle rows with errors"Accessible label for the radio group.
disabledboolean | undefined-
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitUpdatesToggleProps

PropTypeDefaultDescription
title*ReactNode-Heading, e.g. "Also update 3 existing records".
description*ReactNode-Helper copy shown under the heading; typically differs by `checked`.
checked*boolean-
onCheckedChange*(checked: boolean) => void-
iconReactNode-Icon rendered in the leading badge. Omit for no icon.
disabledboolean | undefined-
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitValuesBannerProps

PropTypeDefaultDescription
targetIds*readonly string[]-Ids of the rows missing a value, e.g. row ids with a blank password cell.
title*ReactNode-Heading, e.g. "3 rows need a password". Recomputed by the caller as `targetIds` changes.
description*ReactNode-Helper copy explaining what the action does.
actionLabel*ReactNode-Label for the action button when idle, e.g. "Generate all".
iconReactNode-Icon rendered in the leading badge and on the action button.
onGenerate*(ids: readonly string[]) => void | Promise<void>-Produces the value for each target id and applies them in one update. Deliberately synchronous-per-id, single async apply: filling values in a loop against a single-row update callback tends to revalidate against a stale row list, so this hands back every id/value pair at once.
disabledboolean | undefined-
classNamestring | undefined-
data-testidstring | undefined-

CsvImportKitSelectOption

PropTypeDefaultDescription
value*string-Unique option value.
labelstring | undefined-Rendered label. Falls back to `value` when omitted.
sourcestring | undefined-Short badge shown after the label, e.g. "from CSV".

CsvImportKitSelectProps

PropTypeDefaultDescription
valuestring | undefined-
onChange*(value: string) => void-
options*readonly CsvImportKitSelectOption[]-Options in display order. De-duplicated by `value` (case-insensitive), first occurrence wins.
placeholderstring | undefined"Select value"
clearLabelstring | undefined-Rendered as a value-less option and used as the "cleared" placeholder. Omit to require a value.
errorstring | undefined-
disabledboolean | undefined-
classNamestring | undefined-
data-testidstring | undefined-

Supporting types

export type CsvImportKitBannerTone = "error" | "warning"
export type CsvImportKitReviewMode = "fix" | "skip"

npm dependencies

lucide-react@^1.7.0

Changelog

csv-import-kit

0.1.1

  • Initial release: a generic modal shell and building-block set for a CSV bulk-import flow - drop zone, selected-file chip, error/warning banner, success state, sticky footer, fix/skip mode toggle, apply-updates toggle, bulk-fill-blank-field banner, and a labeled/deduplicated select for review rows - plus CSV escaping/export and secure temporary-value helpers.