Edit Organization Block
EditOrganization is a controlled organization-edit form block built on MUI, with nested sections for company display assets, address, company details, and submit actions.
Installationโ
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-edit-organization-block@0.1.0
yarn add @nodeblocks/frontend-edit-organization-block@0.1.0
pnpm add @nodeblocks/frontend-edit-organization-block@0.1.0
bun add @nodeblocks/frontend-edit-organization-block@0.1.0
What You Needโ
| Item | Why it matters |
|---|---|
data | Controlled form state. The stock shape includes address, company, industry, overview, establishment date, and optional icon / logo media values. |
onDataChange | Receives 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. |
companyName (optional) | Display-only company name shown in Form.CompanyDisplay.CompanyName (not part of data). |
labels / placeholders / selectOptions (optional) | Root copy and select option overrides for the default fields. |
onSearchAddressClick (optional) | Enables the postal-code search button in CompanyAddress.PostCode. |
dateFormat / dateLuxon / locale (optional) | Control establishment-date display format, storage parsing, and MUI date-picker locale. |
iconFns / logoFns / uploadGuidelinesText (optional) | Optional image action callbacks and upload guideline copy for the company display section. |
children (optional) | Use compound sections or a block override function. |
EditOrganization does not own form state. Keep data in your app and pass updates back through onDataChange. data.icon and data.logo can be File, { url, type?, id? }, or null. Establishment dates are stored as yyyy-MM-dd strings by default.
Code Examplesโ
- Quick Start
- Labels and Copy
- Form Errors
- Compound Components
- Block Override
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Sample Company Ltd." uploadGuidelinesText="Use a square PNG or JPEG icon and a wide horizontal logo. Max 5 MB per file." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Acme Corporation" uploadGuidelinesText="Prefer a square icon and a wide logo. Replacements can take a few minutes to appear." labels={{ title: 'Edit your organization', companyName: 'Legal company name', companyIcon: 'Company icon', companyLogo: 'Company logo', locationTitle: 'Head office location', postcode: 'Postal code', postcodeButton: 'Find address', prefecture: 'Prefecture', city: 'City', townAddress: 'Street address', representativeContact: 'Representative phone', homePageUrl: 'Website', companyCapital: 'Capital', companySize: 'Headcount', representativePersonName: 'Representative name', industryCategory: 'Industry category', industry: 'Industry', companyOverview: 'Company overview', businessDescription: 'Business description', establishmentDate: 'Date established', submitButton: 'Save changes', }} placeholders={{ postcode: 'Enter the postal code', prefecture: 'Select a prefecture', city: 'Enter the city', townAddress: 'Enter the street and building', representativeContact: 'Enter a phone number', homePageUrl: 'https://example.com', companyCapital: 'Enter capital', companySize: 'Enter headcount', representativePersonName: 'Enter representative name', industryCategory: 'Select a category', industry: 'Select an industry', companyOverview: 'Summarize the company', businessDescription: 'Describe the business', }} selectOptions={{ industryCategory: [ {value: 'Information technology', label: 'Information technology'}, {value: 'Manufacturing', label: 'Manufacturing'}, ], industry: [ {value: 'Software development', label: 'Software development'}, {value: 'Cloud and IT services', label: 'Cloud and IT services'}, ], }} onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
Override copy with root labels, placeholders, and selectOptions, or customize individual compound sections. companyName, uploadGuidelinesText, currencySymbol, and quantityLabel are not part of labels.
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const {[meta.name]: _removed, ...restErrors} = errors; let nextErrors = restErrors; if (meta.cause === 'blur') { nextErrors = {...restErrors}; const value = nextData[meta.name]; if (value === '' || value == null || (typeof value === 'string' && !value.trim())) { nextErrors[meta.name] = 'This field is required.'; } } setErrors(nextErrors); setData(nextData); }; return ( <EditOrganization data={data} companyName="Sample Company Ltd." errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} /> ); }
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Acme Corporation" uploadGuidelinesText="Use a square PNG or JPEG icon and a wide horizontal logo." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} > <EditOrganization.Title>Edit your organization</EditOrganization.Title> <EditOrganization.Form> <EditOrganization.Form.CompanyDisplay> <EditOrganization.Form.CompanyDisplay.CompanyName /> <EditOrganization.Form.CompanyDisplay.CompanyIcon /> <EditOrganization.Form.CompanyDisplay.CompanyLogo /> <EditOrganization.Form.CompanyDisplay.UploadGuidelines /> </EditOrganization.Form.CompanyDisplay> <EditOrganization.Form.CompanyInformation> <EditOrganization.Form.CompanyInformation.CompanyAddress> <EditOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> Head office location </EditOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <EditOrganization.Form.CompanyInformation.CompanyAddress.PostCode /> <EditOrganization.Form.CompanyInformation.CompanyAddress.Prefecture /> <EditOrganization.Form.CompanyInformation.CompanyAddress.City /> <EditOrganization.Form.CompanyInformation.CompanyAddress.TownAddress /> <EditOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact /> </EditOrganization.Form.CompanyInformation.CompanyAddress> <EditOrganization.Form.CompanyInformation.CompanyCapital currencySymbol="$" /> <EditOrganization.Form.CompanyInformation.CompanySize quantityLabel="employees" /> <EditOrganization.Form.CompanyInformation.IndustryCategory /> <EditOrganization.Form.CompanyInformation.Industry /> <EditOrganization.Form.CompanyInformation.HomePageUrl /> <EditOrganization.Form.CompanyInformation.CompanyOverview /> <EditOrganization.Form.CompanyInformation.BusinessDescription /> <EditOrganization.Form.CompanyInformation.EstablishmentDate /> <EditOrganization.Form.CompanyInformation.RepresentativePersonName /> </EditOrganization.Form.CompanyInformation> <EditOrganization.Form.SubmitButton>Save changes</EditOrganization.Form.SubmitButton> </EditOrganization.Form> </EditOrganization> ); }
function Example() { const defaultData = { postcode: '', cityTownVillage: '', townStreetBuilding: '', representativePhoneNumber: '', companyUrl: '', prefecture: '', capital: '', numberOfEmployees: '', representativePersonName: '', industryCategory: '', industry: '', companyOverview: '', businessDescription: '', establishmentDate: '', icon: null, logo: null, }; const [data, setData] = React.useState(defaultData); return ( <EditOrganization data={data} companyName="Sample Company Ltd." onDataChange={nextData => { setData(nextData); }} onSearchAddressClick={() => { setData(current => ({...current})); }} onSubmit={event => { event.preventDefault(); }} > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { ...defaultBlocks, customNotice: ( <div style={{ width: '100%', border: '1px solid #cddcff', borderRadius: 8, padding: 12, background: '#eef4ff', fontSize: 14, }} > Custom notification added via the block override pattern </div> ), }, blockOrder: ['customNotice', ...defaultBlockOrder], })} </EditOrganization> ); }
When to use block overrides
Use overrides when you need to change order, replace default UI blocks, or inject custom content while preserving shared state handling. The root default render order is title, form. Nested defaults then render companyDisplay, companyInformation, and submitButton.
Important Propsโ
Core Propsโ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
data | EditOrganizationFormData ({ applicationUserName?, applicationUserEmail?, applicationUserPhoneNumber?, postcode?, cityTownVillage?, townStreetBuilding?, representativePhoneNumber?, companyUrl?, prefecture?, capital?, numberOfEmployees?, industryCategory?, industry?, companyOverview?, businessDescription?, establishmentDate?, representativePersonName?, logo?, icon? } or extended Record<string, unknown>) | Yes | - | Controlled form data. Default fields bind to the company address/information UI; icon / logo accept File, { url, type?, id? }, or null. |
onDataChange | (data, meta) => void | Yes | - | Called on updates; meta includes name, value, cause (input, change, blur, clear, reset, programmatic), and optional event. |
errors | { [fieldPath: string]: string | string[] } | No | - | Field errors keyed by bracket-notation data paths. |
onSearchAddressClick | MouseEventHandler<HTMLButtonElement> | No | - | Enables the postal-code search button in CompanyAddress.PostCode. |
companyName | string | No | - | Display-only name for CompanyDisplay.CompanyName. |
iconFns / logoFns | { onAddImage?, onChangeImage?, onDeleteImage? } | No | - | Optional callbacks for icon/logo add, change, and delete actions. |
dateLuxon | { parseDateStringToDateTime; formatDateTimeToString } | No | Strict yyyy-MM-dd parsers | Custom storage parse/format helpers for establishmentDate. |
dateFormat | string | No | 'yyyy/MM/dd' | Luxon display format merged onto EstablishmentDate. |
locale | string | No | 'en-US' | Passed to MUI LocalizationProvider as adapterLocale. |
Content Propsโ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
labels | { title?; companyName?; companyIcon?; companyIconNoImageLabel?; companyIconAddImageLabel?; companyIconChangeImageLabel?; companyIconDeleteImageLabel?; companyLogo?; companyLogoNoImageLabel?; companyLogoAddImageLabel?; companyLogoChangeImageLabel?; companyLogoDeleteImageLabel?; locationTitle?; postcode?; postcodeButton?; prefecture?; city?; townAddress?; representativeContact?; homePageUrl?; companyCapital?; companySize?; representativePersonName?; industryCategory?; industry?; companyOverview?; businessDescription?; establishmentDate?; submitButton? } | No | - | Copy overrides for titles, field labels, image actions, and the submit button. |
placeholders | { postcode?; prefecture?; city?; townAddress?; representativeContact?; homePageUrl?; companyCapital?; companySize?; representativePersonName?; industryCategory?; industry?; companyOverview?; businessDescription? } | No | - | Placeholder text for text and select fields. |
selectOptions | { prefecture?; industryCategory?; industry? } | No | Built-in English prefecture / industry lists | Dropdown options for the select fields. |
uploadGuidelinesText | ReactNode | No | - | Body content for CompanyDisplay.UploadGuidelines. |
Layout and Composition Propsโ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
component | StackProps<'form'>['component'] | No | 'form' | Root container element. |
children | ReactNode or block override function | No | - | Pass JSX children for compound components, or a function to override blocks. |
className | string | No | - | Additional class name on the root container. |
sx | StackProps<'form'>['sx'] | No | - | MUI sx styling for the root container. |
Inherits StackProps<'form'> props except children. The root renders title and form by default. Form then composes CompanyDisplay, CompanyInformation, and SubmitButton.
Default UI Blocksโ
| Block | Built on | Notes |
|---|---|---|
EditOrganization (root) | Stack + LocalizationProvider | Root provider and form shell with responsive padding. Defaults to component="form". |
Title | Typography | Centered h4/h2. Defaults to Edit Organization. |
Form | Stack | Groups company display, company information, and submit. |
Form.CompanyDisplay | Stack | Company name, icon, logo, and upload guidelines. |
Form.CompanyDisplay.CompanyName | Stack + Typography | Shows root companyName. Defaults to label Company Name. |
Form.CompanyDisplay.CompanyIcon | Stack + Box + Button + Divider | Bound to icon. Defaults to label Icon, empty state No image, actions Add / Change / Delete. |
Form.CompanyDisplay.CompanyLogo | Stack + Box + Button + Divider | Bound to logo. Defaults to label Logo, empty state No image, actions Add / Change / Delete. |
Form.CompanyDisplay.UploadGuidelines | Stack + Typography | Renders root uploadGuidelinesText. |
Form.CompanyInformation | Stack | Address, capital, size, industry, overview, dates, and representative name. |
Form.CompanyInformation.CompanyAddress | Stack | Nested address section. |
Form.CompanyInformation.CompanyAddress.LocationTitle | Typography | Defaults to Head Office Location. |
Form.CompanyInformation.CompanyAddress.PostCode | Stack + TextField + Button | name="postcode". Defaults to label Post Code, placeholder Enter the post code, search button Search Address when onSearchAddressClick is set. |
Form.CompanyInformation.CompanyAddress.Prefecture | TextField | name="prefecture". Defaults to label Prefecture, placeholder Select the prefecture, English prefecture options. |
Form.CompanyInformation.CompanyAddress.City | TextField | name="cityTownVillage". Defaults to label City, placeholder Enter the city. |
Form.CompanyInformation.CompanyAddress.TownAddress | TextField | name="townStreetBuilding". Defaults to label Address, placeholder Enter the town, street, and building number. |
Form.CompanyInformation.CompanyAddress.RepresentativeContact | TextField | name="representativePhoneNumber". Defaults to label Representative Phone Number, placeholder Enter the phone number of a representative. |
Form.CompanyInformation.CompanyCapital | Stack + TextField + Typography | name="capital". Defaults to label Capital, placeholder Enter the company's capital, suffix ๅ. |
Form.CompanyInformation.CompanySize | Stack + TextField + Typography | name="numberOfEmployees". Defaults to label Number of Employees, placeholder Enter the company's number of employees, suffix ไบบ. |
Form.CompanyInformation.IndustryCategory | TextField | name="industryCategory". Defaults to label Industry Category, placeholder Select the category. |
Form.CompanyInformation.Industry | TextField | name="industry". Defaults to label Industry, placeholder Select the industry. |
Form.CompanyInformation.HomePageUrl | TextField | name="companyUrl". Defaults to label Home Page URL, placeholder Enter the company's home page URL. |
Form.CompanyInformation.CompanyOverview | TextField | Multiline name="companyOverview". Defaults to label Company Overview. |
Form.CompanyInformation.BusinessDescription | TextField | Multiline name="businessDescription". Defaults to label Business Description. |
Form.CompanyInformation.EstablishmentDate | DatePicker | name="establishmentDate". Defaults to label Establishment Date, display format yyyy/MM/dd, stored value yyyy-MM-dd. |
Form.CompanyInformation.RepresentativePersonName | TextField | name="representativePersonName". Defaults to label Representative Name. |
Form.SubmitButton | Button | variant="contained", size="large", type="submit". Defaults to Submit. |
TypeScriptโ
import {EditOrganization, type EditOrganizationFormData} from '@nodeblocks/frontend-edit-organization-block';
type OrganizationEditData = EditOrganizationFormData & {
internalNotes?: string;
};