Export Data Modal with Format and Field Picker — Free HTML CSS JS Snippet

Export Data Modal with Format and Field Picker · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Three format cards (CSV, JSON, PDF) with exactly one active at a time
Independent field checkboxes with a live checked-count summary line
Export button disables itself automatically when zero fields are selected
Select all button relabels itself to Deselect all once every field is already checked
One updateSummary() function keeps the summary text and button state from ever conflicting
Export click handler collects selected fields and format into a ready-to-send payload shape
Simulated "Preparing..." button state before the modal closes on export
Escape key, backdrop click, and a close button all dismiss the modal
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons

About this UI Snippet

Export Data Modal — Format Selection Plus a Field Checklist with a Live Summary

Screenshot of the Export Data Modal with Format and Field Picker snippet rendered live

A plain "Export CSV" button assumes every visitor wants every field in exactly one format. This modal gives them a real choice: three format cards (CSV, JSON, PDF) and a checklist of individual fields, with a summary line and the export button itself both staying in sync with whatever combination is currently selected.

One `updateSummary()` function reconciles three states at once

Every interaction — clicking a format card, toggling a single checkbox, or clicking "Select all" — calls the same updateSummary() function afterward. It recomputes the checked-field count, rewrites the summary sentence to match both that count and the currently selected format, and enables or disables the export button — all together, so there's no path where the summary text could say "3 fields" while the button is actually disabled for having zero, or where the format name in the summary lags behind the actually-selected format card.

The export button disables itself on a real, checked condition

Rather than always being clickable and letting a zero-field export silently do nothing, exportBtn.disabled is set directly from checkedCount === 0. A visitor who unchecks every field sees the summary line change to an explicit "Select at least one field to export" and watches the button visually grey out — the invalid state is communicated, not just silently prevented.

"Select all" is really "select all or deselect all," decided live

selectAllBtn's own label text updates every time updateSummary() runs, based on fieldCheckboxes.every(cb => cb.checked). When every field is already checked, the button relabels itself "Deselect all" — clicking it then unchecks everything rather than doing nothing (which is what a button permanently labeled "Select all" would confusingly do once everything was already selected).

Format selection uses one shared variable, not per-button state

selectedFormat is a single string variable that every format button's click handler overwrites, and the visual active state is reapplied to all three buttons together via formatButtons.forEach on every click — comparing each button against the one that was actually clicked. This guarantees exactly one format card can ever show as active, since the active class is fully recomputed across all three buttons on every click rather than toggled individually.

The export action is a real state handoff, not a dead end

Clicking "Export" collects the checked fields into a real array via .filter().map() and pairs it with selectedFormat — exactly the payload a real fetch() call to a backend export endpoint would need, shown in a code comment at the point where you'd wire it in. The button shows a brief "Preparing..." state before the modal closes, simulating the round-trip a real export request would involve.

Customizing it

Add a fourth format by adding another .edm-format button with its own data-format value — the click-handler loop and selectedFormat logic already generalize to any number of format buttons. Add or remove fields by editing the .edm-field checkboxes in #edmFields; fieldCheckboxes is queried fresh from the DOM, so no JavaScript changes are needed for the count and summary logic to pick up new fields.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing the state reconciliation by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how updateSummary() keeps the summary text, the export button's disabled state, and the select-all button's own label all derived from the same two pieces of state — the checked field count and the selected format — so none of them can ever show conflicting information after an interaction. The same assistant can help you extend it — ask it to wire the commented-out fetch() call into a real backend export endpoint and handle the response (e.g. triggering a file download or showing a progress toast), add per-format field restrictions (e.g. PDF only supports a subset of fields), or persist the last-used format and field selection to localStorage so returning visitors see their previous choices pre-selected. It's also useful for an accessibility review: ask whether the format cards should use role="radiogroup" semantics instead of plain buttons, given that exactly one is always selected. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a data export modal in plain HTML, CSS, and vanilla JavaScript with a format picker and an independent field checklist — no framework.

Requirements:
- A trigger button that opens a modal (backdrop plus centered dialog with a fade/scale transition), closable via a close button, backdrop click, and the Escape key.
- Inside the modal, a row of format option cards (e.g. CSV, JSON, PDF), each showing a name and a short description, where clicking one selects it and visually deselects the others — exactly one format can be active at any time, tracked in a single shared variable.
- Below the format picker, a grid of individually checkable field checkboxes (at least six), some checked by default and some not, plus a "Select all" button.
- Write one single function that recomputes, together, on every interaction (format click, checkbox toggle, or select-all click): a summary sentence stating how many fields are selected and in what format, and whether the export button should be enabled or disabled — the export button must be disabled specifically when zero fields are checked, with the summary text explicitly explaining why.
- The "Select all" button must relabel itself to "Deselect all" whenever every field checkbox is already checked, and clicking it in that state must uncheck everything rather than doing nothing.
- Clicking the export button (only reachable while enabled) should collect the currently selected format and an array of the checked fields' values, briefly show a "Preparing..." state on the button, then close the modal — include a code comment showing where a real fetch() call to a backend export endpoint would use that collected data.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Open the export modalClick "Export data" to open the format and field picker.
  2. 2
    Choose a formatClick CSV, JSON, or PDF — the active card highlights and the summary line updates.
  3. 3
    Check or uncheck fieldsThe summary and the Export button both update live as you change the selection.
  4. 4
    Try Select all / Deselect allThe button label itself flips depending on whether every field is already checked.
  5. 5
    Uncheck every fieldThe Export button disables and the summary explains why.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Admin dashboards and data table toolbars
Let users export exactly the columns they need instead of a fixed, all-or-nothing CSV dump.
CRM and customer data platforms
Pair with the table export column selector for a matching inline toolbar alternative.
Analytics and reporting tools
Offer PDF for shareable reports and CSV/JSON for further processing from the same export flow.
Learn single-source-of-truth summary patterns
Study how one updateSummary() function prevents the summary text and button state from ever showing conflicting information.
GDPR and data portability request flows
Reuse the field-picker pattern for a "download your data" self-service compliance feature.
Related: Onboarding Checklist Progress Modal
See the Onboarding Checklist Progress Modal for a related checkbox-driven modal pattern.

Got questions?

Frequently Asked Questions

updateSummary() detects checkedCount === 0, changes the summary text to "Select at least one field to export," and sets exportBtn.disabled = true, visually greying out the button so it cannot be clicked until at least one field is checked again.

Every time updateSummary() runs, it checks fieldCheckboxes.every(cb => cb.checked) and sets the button's text to "Deselect all" if every checkbox is already checked, or "Select all" otherwise. Clicking the button itself reads that same allChecked condition to decide whether to check or uncheck every field.

No. selectedFormat is a single shared variable, and clicking any format button loops over all format buttons via formatButtons.forEach, toggling the active class only on the one that was actually clicked. This guarantees exactly one format card is ever shown as active.

It builds a fields array via fieldCheckboxes.filter(checked).map(value) and pairs it with the selectedFormat string — together forming exactly the payload shape a real backend export endpoint would need, shown as a commented-out fetch() call at the point where you would wire in a real request.

Add another button with class edm-format and a data-format="XML" attribute inside #edmFormats, following the same markup pattern as the existing three. The click-handler loop is bound to formatButtons, which is queried from the DOM at load time, so make sure the new button exists before that query runs (i.e., it is present in the initial HTML).

Add or remove a .edm-field label with its checkbox inside #edmFields in the HTML panel. fieldCheckboxes is queried fresh via document.querySelectorAll on page load, so updateSummary() and the select-all logic both automatically include whatever fields are present with no other JavaScript changes needed.