Skip to content

Image uploader#1598

Open
buoren wants to merge 1 commit into
puckeditor:mainfrom
buoren:buoren/image-uploader
Open

Image uploader#1598
buoren wants to merge 1 commit into
puckeditor:mainfrom
buoren:buoren/image-uploader

Conversation

@buoren

@buoren buoren commented Mar 18, 2026

Copy link
Copy Markdown

Closes #13 Image uploader

Description

This PR adds an image upload option to the image field. The URL version is retained, but for image upload optional callbacks are installed in order for the implementor to connect image storage to an api of choice, and autofill the URL if provided.

Changes made

  1. The ImageField component renders a URL text input (for pasting third-party URLs), a file upload dropzone with drag-and-drop (when no value set), or an image preview with remove button (when value is set). Uses onUpload callback for file uploads, validate for pre-upload validation. Supports readOnly.
  2. Styles for the dropzone, URL input, image preview, remove button, loading/error states.
  3. Tests covering empty/populated states, URL input typing and prepopulation, file upload flow, loading state, error handling, validation, remove button, readOnly behavior, drag-and-drop, and type guard.
  4. Full API reference page for the Image field. Documents type, onUpload, placeholder, and validate params with code examples. Explains the dual URL input + upload dropzone behavior.
  5. Added ImageField interface (type: "image", onUpload, validate, placeholder) and added | ImageField to the Field union type.
  6. Added export * from "./ImageField" to the barrel export.
  7. Imported ImageField, added image: ImageField to defaultFields, and added image: overrides.fieldTypes?.image || defaultFields.image to the render useMemo (enabling override support).
  8. Added Image entry to the field types listing (between External and Number).

How to test

  • Render the Puck component with a two-column grid layout using the style prop and confirm it renders in two columns:

Add an image field to a component config using type: "image" with an onUpload handler and render it in <Puck>

  const config = {                                                                                             
    components: {
      Example: {
        fields: {
          heroImage: {
            type: "image",
            label: "Hero Image",
            onUpload: async (file) => URL.createObjectURL(file),
            validate: (file) => {
              if (!file.type.startsWith("image/")) return "Must be an image";
              if (file.size > 5_000_000) return "Max 5MB";
              return null;
            },
          },
        },
        render: ({ heroImage }) => {
          return heroImage ? (
            <img src={heroImage} alt="" style={{ maxWidth: "100%" }} />
          ) : (
            <p>No image selected</p>
          );
        },
      },
    },
  };

  <Puck config={config} data={{ content: [], root: {} }} />

Test in implementation
Screenshot 2026-03-18 at 05 39 33
Screenshot 2026-03-18 at 05 40 11

Notes

I've contributed this because I need it for an app I'm working on, and thought this might be useful for others as well. I'm happy to grant access if anyone wants to see it in action at: https://demo.progressionworkshops.com/back-office (please contact me for some test logins).

@vercel

vercel Bot commented Mar 18, 2026

Copy link
Copy Markdown

@buoren is attempting to deploy a commit to the Puck Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Image uploader

1 participant