Skip to main content

Edit Product Block

EditProduct is a controlled product-edit form block built on MUI, with nested sections for media, product details, inventory, and submit actions.

Installation

npm install @nodeblocks/frontend-edit-product-block

What You Need

ItemWhy it matters
dataControlled form state. The stock shape includes title, categoryId, typeId, optionId, quantity, description, details, prefecture, city, onlineAvailability, inventoryNotes, availableFrom, availableUntil, additionalDetails, image, and tags.
onDataChangeReceives the next data snapshot plus metadata for the changed field path (meta.name), latest value (meta.value), cause (meta.cause), and optional event (meta.event).
errors (optional)Field-level validation keyed by bracket-notation paths.
onRejectAttachment (optional)Receives rejected upload files from the image dropzone with a DropzoneFileError.
labels (optional)Copy for section titles, field labels, the dropzone, and the submit button.
placeholders (optional)Placeholder text for text and select fields.
selectOptions (optional)Dropdown options for category, type, option, and prefecture fields.
tagTypes / tags (optional)Drive the tag picker in the basic-info section.
children (optional)Use compound sections or a block override function.
Controlled component

EditProduct does not own form state. Keep data in your app and pass updates back through onDataChange. data.image can be File, { url, type?, id? }, or null, and data.tags is an array of Tag objects.

Code Examples

Live Editor
function Example() {
  const defaultData = {
    title: '',
    categoryId: '',
    typeId: '',
    optionId: '',
    quantity: '',
    description: '',
    details: '',
    prefecture: '',
    city: '',
    onlineAvailability: false,
    inventoryNotes: '',
    availableFrom: '',
    availableUntil: '',
    additionalDetails: '',
    image: null,
    tags: [],
  };

  const [data, setData] = React.useState(defaultData);

  const selectOptions = {
    categoryOptions: [
      { value: 'electronics', label: 'Electronics' },
      { value: 'clothing', label: 'Clothing' },
      { value: 'home', label: 'Home & Garden' },
    ],
    typeOptions: [
      { value: 'physical', label: 'Physical' },
      { value: 'digital', label: 'Digital' },
      { value: 'service', label: 'Service' },
    ],
    optionOptions: [
      { value: 'standard', label: 'Standard' },
      { value: 'premium', label: 'Premium' },
      { value: 'custom', label: 'Custom' },
    ],
    prefectureOptions: [
      { value: 'Tokyo', label: 'Tokyo' },
      { value: 'Osaka', label: 'Osaka' },
      { value: 'Fukuoka', label: 'Fukuoka' },
    ],
  };

  const tagTypes = [
    { id: '100', label: 'Product highlights' },
    { id: '200', label: 'Materials & care' },
  ];

  const tags = [
    { id: '101', typeId: '100', label: 'Best seller' },
    { id: '102', typeId: '100', label: 'New arrival' },
    { id: '201', typeId: '200', label: 'Organic / natural materials' },
    { id: '202', typeId: '200', label: 'Contains recycled content' },
  ];

  return (
    <EditProduct
      data={data}
      selectOptions={selectOptions}
      tagTypes={tagTypes}
      tags={tags}
      onDataChange={(nextData) => {
        setData(nextData);
      }}
      onSubmit={(e) => {
        e.preventDefault();
      }}
    />
  );
}
Result
Loading...

Important Props

Core Props

PropTypeRequiredDefaultDescription
dataEditProductFormData ({ title, categoryId, typeId, optionId, quantity, description, details, tags, prefecture, city, onlineAvailability, inventoryNotes, availableFrom, availableUntil, additionalDetails, image } or extended Record<string, unknown>)Yes-Controlled form state.
onDataChange(data: EditProductFormData, meta: { name: string; value: unknown; cause: one of input, change, blur, clear, reset, programmatic; event?: React.SyntheticEvent }) => voidYes-Called whenever a field changes. meta.name uses bracket-notation paths.
errors{ [fieldPath: string]: string | string[] }NoundefinedValidation feedback keyed by the field path, including nested array paths.
onRejectAttachment(file: File, error: DropzoneFileError) => voidNoundefinedCalled when the dropzone rejects an upload.
tagTypesTagType[] ({ id: string; label: string }[])NoundefinedTag groups used by BasicInfo.TagsField.
tagsTag[] ({ id: string; typeId?: string; label: string }[])NoundefinedAvailable tag options used by BasicInfo.TagsField.

Content Props

PropTypeRequiredDefaultDescription
labels{ mainInfoSectionTitle?: string; titleField?: string; dropzoneDropHere?: string; dropzoneUploadImage?: string; dropzoneSubtitle?: string; dropzoneImageAlt?: string; dropzoneOptionsButton?: string; dropzoneReplaceFile?: string; dropzoneDeleteFile?: string; basicInfoSectionTitle?: string; categoryField?: string; typeField?: string; optionField?: string; quantityField?: string; quantityUnit?: string; descriptionField?: string; detailsField?: string; tagsField?: string; additionalInfoTitle?: string; additionalInfoSubtitle?: string; prefectureField?: string; cityField?: string; onlineAvailabilityField?: string; inventoryNotesField?: string; availableFromField?: string; availableUntilField?: string; additionalDetailsField?: string; submitButton?: string }NoundefinedCopy for section titles, field labels, dropzone text, image alt text, the quantity unit suffix, and the submit button.
placeholders{ titleField?: string; categoryField?: string; typeField?: string; optionField?: string; quantityField?: string; descriptionField?: string; detailsField?: string; prefectureField?: string; cityField?: string; inventoryNotesField?: string; additionalDetailsField?: string }NoundefinedPlaceholder text for the text and select fields.
selectOptions{ categoryOptions?: EditProductSelectOption[]; typeOptions?: EditProductSelectOption[]; optionOptions?: EditProductSelectOption[]; prefectureOptions?: EditProductSelectOption[] }NoundefinedDropdown options used by the select fields.

Layout and Composition Props

PropTypeRequiredDefaultDescription
componentStackProps<'form'>['component']No'form'Root element rendered by the outer stack.
childrenBlocksOverride<typeof defaultEditProductBlocks, CustomBlocks>NoundefinedUse JSX compound sections or a function that returns blocks and blockOrder.

Inherited props come from StackProps<'form'> with children replaced by the block override API, so standard form/container props such as className, sx, id, and onSubmit are available.

Default UI Blocks

BlockBuilt onNotes
EditProductStackRoot form shell with responsive padding and max width.
MainInfoStackSection for the upload dropzone and title field.
MainInfo.DropzoneBox + Menu + MenuItem + react-dropzoneFile upload surface for image; default text includes Drop the image here..., Upload product image, PNG, JPG up to 2MB, Options, Select a new file, Delete, and the alt text Selected.
MainInfo.TitleFieldTextFieldMultiline title input with a character counter. Defaults to label Title and placeholder Enter title.
BasicInfoStackProduct detail section with category, type, quantity, description, details, and tags.
BasicInfo.SectionTitleTypographyDefaults to Basic Information.
BasicInfo.CategoryFieldSelectFieldSelect field bound to categoryId. Defaults to label Category and placeholder Select category.
BasicInfo.TypeFieldSelectFieldSelect field bound to typeId. Defaults to label Type and placeholder Select type.
BasicInfo.OptionFieldSelectFieldSelect field bound to optionId. Defaults to label Option and placeholder Select option.
BasicInfo.QuantityFieldFormControl + OutlinedInputQuantity input bound to quantity, with unit text. Defaults to label Quantity, placeholder Enter quantity, unit pcs.
BasicInfo.DescriptionFieldTextFieldMultiline description field bound to description. Defaults to Description / Describe the product.
BasicInfo.DetailsFieldTextFieldMultiline details field bound to details. Defaults to Details / Enter details.
BasicInfo.TagsFieldFormControl + FormGroup + CheckboxRenders grouped tag checkboxes. Only renders when tagTypes and tags are provided. Defaults to Tags.
AdditionalInfoStackInventory and location section.
AdditionalInfo.TitleTypographyDefaults to Inventory.
AdditionalInfo.SubtitleTypographyDefaults to Location.
AdditionalInfo.PrefectureFieldSelectFieldSelect field bound to prefecture. Defaults to label Prefecture and placeholder Select prefecture.
AdditionalInfo.CityFieldTextFieldText field bound to city. Defaults to label City and placeholder Enter city.
AdditionalInfo.OnlineAvailabilityFieldFormControlLabel + CheckboxBoolean checkbox bound to onlineAvailability. Defaults to Online Availability.
AdditionalInfo.InventoryNotesFieldTextFieldMultiline notes field bound to inventoryNotes. Defaults to Inventory Notes / Notes about inventory.
AdditionalInfo.AvailableFromFieldTimePickerTime field bound to availableFrom and stored as HH:mm. Defaults to Available From.
AdditionalInfo.AvailableUntilFieldTimePickerTime field bound to availableUntil and stored as HH:mm. Defaults to Available Until.
AdditionalInfo.AdditionalDetailsFieldTextFieldMultiline field bound to additionalDetails. Defaults to Additional Details / Enter additional details.
ActionsStack + ButtonSubmit area centered under the form.
Actions.SubmitButtonButtonvariant="contained", size="large", type="submit", with a check icon. Defaults to Submit.

Extra field primitives

PrimitiveMain PropsInheritsBuilt onNotes
TextFieldname, label, placeholder, requiredTextFieldProps plus context getValue, setValue, and errorsTextFieldControlled text input used by the stock layout.
NumberFieldname, label, placeholder, requiredTextFieldProps plus context getValue, setValue, and errorsTextFieldNumeric text field with type="number" and min=0.
SelectFieldname, options, placeholder, labelTextFieldProps plus context getValue, setValue, and errorsTextFieldSelect input that shows placeholder text when no value is selected.
CheckboxFieldname, labelFormControlLabelProps with control fixed to MUI CheckboxFormControlLabel + CheckboxControlled boolean field used by OnlineAvailabilityField.
TimeFieldname, label, required, helperTextTimePickerProps plus context getValue, setValue, and errorsTimePickerStores time values as HH:mm strings through DateTime conversion.

TypeScript

export type EditProductFormData =
| {
title: string;
categoryId: string;
typeId: string;
optionId: string;
quantity: string;
description: string;
details: string;
tags: Tag[];
prefecture: string;
city: string;
onlineAvailability: boolean;
inventoryNotes: string;
availableFrom: string;
availableUntil: string;
additionalDetails: string;
image: { url: string; type?: string; id?: string } | File | null;
}
| Record<string, unknown>;

export interface TagType {
id: string;
label: string;
}

export interface Tag {
id: string;
typeId?: string;
label: string;
}

export type EditProductSelectOption = {
value: string;
label: string;
};