Edit Basic Information Block
EditBasicInformation is a controlled address-and-profile form block built on MUI.
Installationâ
- npm
- yarn
- pnpm
- bun
npm install @nodeblocks/frontend-edit-basic-information-block
yarn add @nodeblocks/frontend-edit-basic-information-block
pnpm add @nodeblocks/frontend-edit-basic-information-block
bun add @nodeblocks/frontend-edit-basic-information-block
What You Needâ
| Item | Why it matters |
|---|---|
data | Controlled form state. The default shape uses NameInput, FuriganaInput, PostalCodeInput, PrefectureSelect, CityInput, AddressInput, and PhoneInput. |
onDataChange | Receives the next data snapshot plus metadata about the edited field path. |
errors (optional) | Field-level validation feedback keyed by field path. |
labels (optional) | Copy for the title, subtitle, input labels, search button, and submit button. |
placeholders (optional) | Placeholder text for text inputs and the prefecture select. |
selectOptions (optional) | Custom option list for the prefecture select. |
onSearchAddressClick (optional) | Handles the postal-code address lookup button. |
blockSpacingBefore (optional) | Adjusts spacing before specific default blocks or override blocks. |
children (optional) | Use compound components or block override rendering. |
EditBasicInformation does not own form state. Keep data in your app and pass updates back through onDataChange. The stock shape is the named-field object used in Storybook, and FieldErrorMap uses bracket-notation paths if you need nested validation later.
Code Examplesâ
- Quick Start
- Labels and Copy
- Form Errors
- Compound Components
- Block Override
function Example() { const defaultData = { NameInput: 'ć±±ç°ć€Șé', FuriganaInput: 'ă€ăăăżăăŠ', PostalCodeInput: '1234567', PrefectureSelect: 'æ±äșŹéœ', CityInput: 'ćžćșçșæăć „ć', AddressInput: 'çșćă»çȘć°ă»ć»șç©ăć „ć', PhoneInput: 'é»è©±çȘć·ăć „ćïŒăă€ăăłăȘăă§ć „ćïŒ', }; const [data, setData] = React.useState(defaultData); return ( <EditBasicInformation data={data} onDataChange={(nextData) => { setData(nextData); }} onSearchAddressClick={() => { setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { NameInput: 'ć±±ç°ć€Șé', FuriganaInput: 'ă€ăăăżăăŠ', PostalCodeInput: '1234567', PrefectureSelect: 'æ±äșŹéœ', CityInput: 'ćžćșçșæăć „ć', AddressInput: 'çșćă»çȘć°ă»ć»șç©ăć „ć', PhoneInput: 'é»è©±çȘć·ăć „ćïŒăă€ăăłăȘăă§ć „ćïŒ', }; const [data, setData] = React.useState(defaultData); const labels = { title: 'Basic information', subtitle: 'Fields marked * are required.', nameInput: 'Full name', furiganaInput: 'Full name in kana', postalCodeInput: 'Postal code', searchAddressButton: 'Look up address', prefectureSelect: 'Prefecture', cityInput: 'City', addressInput: 'Street address', phoneInput: 'Phone number', submitButton: 'Save', }; const placeholders = { nameInput: 'Enter your full name', furiganaInput: 'Enter furigana', postalCodeInput: '1234567', prefectureSelect: 'Select a prefecture', cityInput: 'Enter city', addressInput: 'Enter street address', phoneInput: 'Enter phone number', }; const selectOptions = { prefectureSelect: [ { value: 'æ±äșŹéœ', label: 'æ±äșŹéœ' }, { value: '性éȘćș', label: '性éȘćș' }, { value: 'çŠćČĄç', label: 'çŠćČĄç' }, ], }; return ( <EditBasicInformation data={data} onDataChange={(nextData) => { setData(nextData); }} labels={labels} placeholders={placeholders} selectOptions={selectOptions} onSearchAddressClick={() => { setData((current) => ({ ...current })); }} /> ); }
This block does not have URL props. Put text overrides on the root labels and placeholders, or override individual subcomponents if you need custom layout or copy.
function Example() { const defaultData = { NameInput: '', FuriganaInput: '', PostalCodeInput: '', PrefectureSelect: '', CityInput: '', AddressInput: '', PhoneInput: '', }; const [data, setData] = React.useState(defaultData); const [errors, setErrors] = React.useState({}); const handleDataChange = (nextData, meta) => { const { [meta.name]: _removed, ...restErrors } = errors; let nextErrors = restErrors; // Validate required fields on blur (same pattern as storybook) if (meta.cause === 'blur') { nextErrors = { ...restErrors }; const value = nextData[meta.name]; if (value === '' || (typeof value === 'string' && !value.trim())) { nextErrors[meta.name] = 'This field is required.'; } } setErrors(nextErrors); setData(nextData); }; return ( <EditBasicInformation data={data} errors={Object.keys(errors).length ? errors : undefined} onDataChange={handleDataChange} onSearchAddressClick={() => { setData((current) => ({ ...current })); }} /> ); }
function Example() { const defaultData = { NameInput: 'ć±±ç°ć€Șé', FuriganaInput: 'ă€ăăăżăăŠ', PostalCodeInput: '1234567', PrefectureSelect: 'æ±äșŹéœ', CityInput: 'ćžćșçșæăć „ć', AddressInput: 'çșćă»çȘć°ă»ć»șç©ăć „ć', PhoneInput: 'é»è©±çȘć·ăć „ćïŒăă€ăăłăȘăă§ć „ćïŒ', }; const [data, setData] = React.useState(defaultData); return ( <EditBasicInformation data={data} onDataChange={(nextData) => { setData(nextData); }} labels={{ searchAddressButton: 'äœæăæ€çŽą' }} onSearchAddressClick={() => { setData((current) => ({ ...current })); }} > <EditBasicInformation.Title>Basic information</EditBasicInformation.Title> <Stack spacing={3}> <EditBasicInformation.Subtitle>Fields marked * are required.</EditBasicInformation.Subtitle> <EditBasicInformation.NameInput required={false} /> <EditBasicInformation.FuriganaInput required={false} /> <EditBasicInformation.PostalCodeInput required={false} /> <EditBasicInformation.PrefectureSelect required={false} /> <EditBasicInformation.CityInput required={false} /> <EditBasicInformation.AddressInput required={false} /> <EditBasicInformation.PhoneInput required={false} /> </Stack> <EditBasicInformation.SubmitButton>Save</EditBasicInformation.SubmitButton> </EditBasicInformation> ); }
function Example() { const defaultData = { NameInput: 'ć±±ç°ć€Șé', FuriganaInput: 'ă€ăăăżăăŠ', PostalCodeInput: '1234567', PrefectureSelect: 'æ±äșŹéœ', CityInput: 'ćžćșçșæăć „ć', AddressInput: 'çșćă»çȘć°ă»ć»șç©ăć „ć', PhoneInput: 'é»è©±çȘć·ăć „ćïŒăă€ăăłăȘăă§ć „ćïŒ', }; const [data, setData] = React.useState(defaultData); return ( <EditBasicInformation data={data} onDataChange={(nextData) => { setData(nextData); }} onSearchAddressClick={() => { setData((current) => ({ ...current })); }} > {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, customBlock: <Alert severity="info">Custom notification</Alert>, }, blockOrder: ['customBlock', ...defaultBlockOrder], })} </EditBasicInformation> ); }
defaultBlockOrder includes the stock layout order for title, subtitle, inputs, and submit button. The root renderer also includes an internal input primitive in defaultBlocks, but it is filtered out of the visible default order. blockSpacingBefore applies to default blocks and function-based overrides, but not to raw JSX compound children.
Important Propsâ
Core Propsâ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
data | EditBasicInformationFormData | Yes | - | Controlled form state. The default story shape uses the named fields listed above. |
onDataChange | (data: EditBasicInformationFormData, meta: { name: string; value: unknown; cause: one of input, change, blur, clear, reset, programmatic; event?: React.SyntheticEvent }) => void | Yes | - | Called whenever a field updates. meta.name uses bracket-notation paths. |
errors | { [fieldPath: string]: string | string[] } | No | undefined | Validation feedback keyed by field path. |
onSearchAddressClick | MouseEventHandler<HTMLButtonElement> | No | undefined | Shown as the postal-code search action when provided. |
Content Propsâ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
labels | { title?: string; subtitle?: string; nameInput?: string; furiganaInput?: string; postalCodeInput?: string; searchAddressButton?: string; prefectureSelect?: string; cityInput?: string; addressInput?: string; phoneInput?: string; submitButton?: string } | No | undefined | Copy for the title, helper text, input labels, search button, and submit button. |
placeholders | { nameInput?: string; furiganaInput?: string; postalCodeInput?: string; prefectureSelect?: string; cityInput?: string; addressInput?: string; phoneInput?: string } | No | undefined | Placeholder copy for the text fields and prefecture select. |
selectOptions | { prefectureSelect?: { value: string; label: string }[] } | No | undefined | Custom options for the prefecture select. |
Layout and Composition Propsâ
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
component | StackProps<'form'>['component'] | No | 'form' | Root element rendered by the outer stack. |
blockSpacingBefore | Partial<Record<string, number | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl', number>>>> | No | { subtitle: 4, nameInput: { xs: 4, sm: 3 }, submitButton: 4 } | Extra spacing before named default blocks or function-based override blocks. |
children | BlocksOverride<typeof defaultBlocks, CustomBlocks> | No | undefined | Use JSX compound components 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, and id are available.
Default UI Blocksâ
| Block | Built on | Notes |
|---|---|---|
EditBasicInformation | Stack | Root form shell with padding and responsive layout. |
Title | Typography | variant="h4", component="h2", bold and centered. Defaults to ćșæŹæ
ć ±ăç·šé. |
Subtitle | Typography | variant="body2". Defaults to * ăŻćż
é äșé
ă§ă. |
NameInput | TextField | Defaults to label æ°ć and placeholder æ°ćăć
„ć. |
FuriganaInput | TextField | Defaults to label ăăȘăŹă and placeholder ăăȘăŹăăć
„ć. |
PostalCodeInput | TextField + Button | Defaults to label é”äŸżçȘć·, placeholder é”äŸżçȘć·ăć
„ć, and search button äœæăæ€çŽą. |
PrefectureSelect | FormControl + InputLabel + Select | Defaults to label éœéćșç, placeholder éœéćșçăéžæ, and built-in prefecture options. |
CityInput | TextField | Defaults to label ćžćșçșæ and placeholder ćžćșçșæăć
„ć. |
AddressInput | TextField | Defaults to label çșćă»çȘć°ă»ć»șç© and placeholder çșćă»çȘć°ă»ć»șç©ăć
„ć. |
PhoneInput | TextField | Defaults to label éŁç”Ąć
é»è©±çȘć· and placeholder é»è©±çȘć·ăć
„ćïŒăă€ăăłăȘăă§ć
„ćïŒ. |
SubmitButton | Button | variant="contained", size="large", type="submit", centered with a wide desktop width. Defaults to äżć. |
Extra field primitivesâ
| Primitive | Main Props | Inherits | Built on | Notes |
|---|---|---|---|---|
Input | name, label, placeholder, required | TextFieldProps plus getValue, setValue, and errors from context | TextField | A controlled text field primitive used by the stock layout. Available for custom flows, but not rendered directly in the default block order. |
TypeScriptâ
type EditBasicInformationFormData =
| {
NameInput: string;
FuriganaInput: string;
PostalCodeInput: string;
PrefectureSelect: string;
CityInput: string;
AddressInput: string;
PhoneInput: string;
}
| Record<string, unknown>;