Create Organization Block
CreateOrganization is a controlled organization application form built on MUI.
Installationโ
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-create-organization-block
yarn add @nodeblocks/frontend-create-organization-block
pnpm add @nodeblocks/frontend-create-organization-block
bun add @nodeblocks/frontend-create-organization-block
What You Needโ
| Item | Why it matters |
|---|---|
data | Single source of truth for form state; the shape can be extended with custom fields such as establishmentDate |
onDataChange | Receives updated state plus metadata for validation, analytics, or side effects |
errors (optional) | Field errors keyed by data path |
termsOfUseUrl (optional) | Target URL for the terms-of-use link in the compliance section |
privacyAgreementUrl (optional) | Target URL for the privacy-policy link in the compliance section |
onSearchAddressClick (optional) | Handles the postal-code search button in CompanyAddress.PostCode |
CreateOrganization does not own form state. Keep state in your app and pass it through data. The default form data covers account-holder fields, company details, compliance checkboxes, and can be extended for custom fields such as establishmentDate.
Code Examplesโ
- Quick Start
- Labels and URLs
- Form Errors
- Compound Components
- Block Override
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > <CreateOrganization.Title>Apply for your organization</CreateOrganization.Title> <CreateOrganization.Description>Please fill out the form below to register your organization.</CreateOrganization.Description> <CreateOrganization.Form> <CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.AccountHolder.SectionTitle>Account holder</CreateOrganization.Form.AccountHolder.SectionTitle> <CreateOrganization.Form.AccountHolder.Name label="Full name" placeholder="Enter your full name" /> <CreateOrganization.Form.AccountHolder.Email label="Email address" placeholder="Enter your email address" /> <CreateOrganization.Form.AccountHolder.Contact label="Phone number" placeholder="Enter your phone number" /> </CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.CompanyInformation.SectionTitle>Company details</CreateOrganization.Form.CompanyInformation.SectionTitle> <CreateOrganization.Form.CompanyInformation.CompanyName label="Company name" placeholder="Enter the company name" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle>Head office location</CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <CreateOrganization.Form.CompanyInformation.CompanyAddress.PostCode searchAddressLabel="Find address" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.Prefecture label="Prefecture" placeholder="Select a prefecture" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.City label="City / Town / Village" placeholder="Enter the city" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.TownAddress label="Street address" placeholder="Enter the street address" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativePersonName label="Representative name" placeholder="Enter the representative name" /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact label="Representative phone number" placeholder="Enter the representative phone number" /> </CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyCapital label="Capital" placeholder="Enter the capital" /> <CreateOrganization.Form.CompanyInformation.CompanySize label="Number of employees" placeholder="Enter the employee count" /> <CreateOrganization.Form.CompanyInformation.HomePageUrl label="Website" placeholder="Enter the website URL" /> <CreateOrganization.Form.CompanyInformation.AdditionalInformation label="Additional information" placeholder="Enter any extra details" /> </CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.Compliance> <CreateOrganization.Form.Compliance.CheckUserAgreement termsOfUseUrl="/terms-of-use" /> <CreateOrganization.Form.Compliance.CheckPrivacyAgreement privacyAgreementUrl="/privacy-policy" /> </CreateOrganization.Form.Compliance> <CreateOrganization.Form.SubmitButton>Create organization</CreateOrganization.Form.SubmitButton> </CreateOrganization.Form> </CreateOrganization> ); }
labelsThis block does not expose a root labels prop. Override copy on the nested pieces instead: Title, Description, Form.AccountHolder.*, Form.CompanyInformation.*, Form.CompanyInformation.CompanyAddress.*, Form.Compliance.*, Form.SubmitButton, and CompanyAddress.PostCode.searchAddressLabel.
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const { [meta.name]: _removed, ...restErrors } = errors; const nextErrors = { ...restErrors }; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { 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 ( <CreateOrganization data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > <CreateOrganization.Title>Create your organization</CreateOrganization.Title> <CreateOrganization.Description>Use the form below to register a new organization.</CreateOrganization.Description> <CreateOrganization.Form> <CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.AccountHolder.SectionTitle>Account holder</CreateOrganization.Form.AccountHolder.SectionTitle> <CreateOrganization.Form.AccountHolder.Name /> <CreateOrganization.Form.AccountHolder.Email /> <CreateOrganization.Form.AccountHolder.Contact /> </CreateOrganization.Form.AccountHolder> <CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.CompanyInformation.SectionTitle>Company information</CreateOrganization.Form.CompanyInformation.SectionTitle> <CreateOrganization.Form.CompanyInformation.CompanyName /> <CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle>Head office location</CreateOrganization.Form.CompanyInformation.CompanyAddress.LocationTitle> <CreateOrganization.Form.CompanyInformation.CompanyAddress.PostCode /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.Prefecture /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.City /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.TownAddress /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativePersonName /> <CreateOrganization.Form.CompanyInformation.CompanyAddress.RepresentativeContact /> </CreateOrganization.Form.CompanyInformation.CompanyAddress> <CreateOrganization.Form.CompanyInformation.CompanyCapital /> <CreateOrganization.Form.CompanyInformation.CompanySize /> <CreateOrganization.Form.CompanyInformation.HomePageUrl /> <CreateOrganization.Form.CompanyInformation.AdditionalInformation /> </CreateOrganization.Form.CompanyInformation> <CreateOrganization.Form.Compliance> <CreateOrganization.Form.Compliance.CheckUserAgreement /> <CreateOrganization.Form.Compliance.CheckPrivacyAgreement /> </CreateOrganization.Form.Compliance> <CreateOrganization.Form.SubmitButton>Submit organization</CreateOrganization.Form.SubmitButton> </CreateOrganization.Form> </CreateOrganization> ); }
function Example() { const defaultData = { applicationUserName: '', applicationUserEmail: '', applicationUserPhoneNumber: '', companyName: '', postcode: '', cityTownVillage: '', townStreetBuilding: '', representivePersonName: '', representativePhoneNumber: '', companyUrl: '', additionalInformation: '', establishmentDate: '', prefecture: '', capital: '', numberOfEmployees: '', userAgreement: '', privacyPolicy: '', }; const [data, setData] = React.useState(defaultData); return ( <CreateOrganization data={data} onDataChange={setData} termsOfUseUrl="/terms-of-use" privacyAgreementUrl="/privacy-policy" onSearchAddressClick={() => { setData((current) => ({ ...current })); }} onSubmit={(event) => { event.preventDefault(); setData((current) => ({ ...current })); }} > {({ 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], })} </CreateOrganization> ); }
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, description, form. DateField is exported separately for custom flows and is not part of the default render.
Important Propsโ
Core Propsโ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
data | CreateOrganizationFormData ({ applicationUserName?, applicationUserEmail?, applicationUserPhoneNumber?, companyName?, postcode?, cityTownVillage?, townStreetBuilding?, representivePersonName?, representativePhoneNumber?, companyUrl?, additionalInformation?, prefecture?, capital?, numberOfEmployees?, userAgreement?, privacyPolicy? } or extended Record<string, unknown>) | Yes | - | Controlled form data object |
onDataChange | (data, meta) => void | Yes | - | Called on updates; meta includes name, value, cause (input, change, blur, clear, reset, programmatic), and optional event |
errors | { [fieldName: string]: string | string[] } | No | undefined | Field errors keyed by data path; common keys include the account-holder fields, company fields, userAgreement, privacyPolicy, and custom extension fields such as establishmentDate |
termsOfUseUrl | string | No | '/terms-of-use' | Target URL for the terms-of-use link in the compliance checkbox |
privacyAgreementUrl | string | No | '/privacy-policy' | Target URL for the privacy-policy link in the compliance checkbox |
onSearchAddressClick | MouseEventHandler<HTMLButtonElement> | No | undefined | Enables the postal-code search button in CompanyAddress.PostCode |
Content Propsโ
No root labels prop is exposed. Override copy in the nested compound components instead.
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 | undefined | Pass JSX children for compound components, or a function to override blocks |
className | string | No | undefined | Additional class name on the root container |
sx | StackProps<'form'>['sx'] | No | undefined | MUI sx styling for the root container |
Inherits StackProps<'form'> props except children. The root renders title, description, and form by default. Form then composes AccountHolder, CompanyInformation, Compliance, and SubmitButton.
Default UI Blocksโ
| Block | MUI base component(s) | Notes |
|---|---|---|
CreateOrganization | Stack | Root provider and layout container; defaults to component="form" with responsive padding |
Title | Typography | Default copy is Create your Organization |
Description | Typography | Default copy explains the application flow and marks required fields |
Form | Stack | Default layout groups account-holder, company information, compliance, and submit sections |
Form.AccountHolder | Stack | Default section title is Contact Information |
Form.AccountHolder.SectionTitle | Typography | Default copy is Contact Information |
Form.AccountHolder.Name | TextField | name="applicationUserName", default label Name, default placeholder Enter your name |
Form.AccountHolder.Email | TextField | name="applicationUserEmail", default label Email, default placeholder Enter your email address |
Form.AccountHolder.Contact | TextField | name="applicationUserPhoneNumber", default label Phone Number, default placeholder Enter your phone number |
Form.CompanyInformation | Stack | Default section title is Company Information |
Form.CompanyInformation.SectionTitle | Typography | Default copy is Company Information |
Form.CompanyInformation.CompanyName | TextField | name="companyName", default label Company Name, default placeholder Enter the company's name |
Form.CompanyInformation.CompanyAddress | Stack | Nested address section that groups post code, prefecture, city, street address, and representative contact fields |
Form.CompanyInformation.CompanyAddress.LocationTitle | Typography | Default copy is Head Office Location |
Form.CompanyInformation.CompanyAddress.PostCode | Stack + TextField + Button | name="postcode", default label Post Code, default placeholder Enter the post code, search button text defaults to Search Address |
Form.CompanyInformation.CompanyAddress.Prefecture | TextField | name="prefecture", default label Prefecture, default placeholder Select the prefecture, options default to the English-prefecture list |
Form.CompanyInformation.CompanyAddress.City | TextField | name="cityTownVillage", default label City, default placeholder Enter the city |
Form.CompanyInformation.CompanyAddress.TownAddress | TextField | name="townStreetBuilding", default label Address, default placeholder Enter the town, street, and building number |
Form.CompanyInformation.CompanyAddress.RepresentativePersonName | TextField | name="representivePersonName", default label Representive Name, default placeholder Enter the name of a representative |
Form.CompanyInformation.CompanyAddress.RepresentativeContact | TextField | name="representativePhoneNumber", default label Representative Phone Number, default placeholder Enter the phone number of a representative |
Form.CompanyInformation.CompanyCapital | Stack + TextField + Typography | name="capital", default label Capital, default placeholder Enter the company's capital, suffix ๅ |
Form.CompanyInformation.CompanySize | Stack + TextField + Typography | name="numberOfEmployees", default label Number of Employees, default placeholder Enter the company's number of employees, suffix ไบบ |
Form.CompanyInformation.HomePageUrl | TextField | name="companyUrl", default label Home Page URL, default placeholder Enter the company's home page URL |
Form.CompanyInformation.AdditionalInformation | TextField | name="additionalInformation", default label Additonal Information, default placeholder Enter a description of the company, multiline enabled |
Form.Compliance | Stack | Default horizontal compliance row on larger screens, stacked vertically on small screens |
Form.Compliance.CheckUserAgreement | FormControl + FormControlLabel + Checkbox + Link | name="userAgreement", default text is I agree to the terms of use. with link target termsOfUseUrl or /terms-of-use (opens in a new tab) |
Form.Compliance.CheckPrivacyAgreement | FormControl + FormControlLabel + Checkbox + Link | name="privacyPolicy", default text is I agree to the privacy policy. with link target privacyAgreementUrl or /privacy-policy (opens in a new tab) |
Form.SubmitButton | Button | Default copy is Submit |
Extra field primitivesโ
| Primitive | MUI base component(s) | Notes |
|---|---|---|
DateField | LocalizationProvider + DatePicker | Exported as CreateOrganization.DateField for custom flows; default display format is yyyy/MM/dd, stored value format is yyyy-MM-dd, and the default locale is en-US |
TypeScriptโ
export type CreateOrganizationFormData =
| {
applicationUserName?: string;
applicationUserEmail?: string;
applicationUserPhoneNumber?: string;
companyName?: string;
postcode?: string;
cityTownVillage?: string;
townStreetBuilding?: string;
representivePersonName?: string;
representativePhoneNumber?: string;
companyUrl?: string;
additionalInformation?: string;
prefecture?: string;
capital?: string;
numberOfEmployees?: string;
userAgreement?: string;
privacyPolicy?: string;
}
| Record<string, unknown>;