Dynamically generate forms with configurable rules for React.js.
npm install @gbyte/dynamic-form
# or
yarn add @gbyte/dynamic-form
# or
pnpm add @gbyte/dynamic-form
import { Form } from '@gbyte/dynamic-form'
export default function DynamicForm() {
return (
<Form
gap={10}
rows={[
{
id: 'account-row',
gap: 10,
columns: [
{
id: 'column-1',
borderWidth: 1,
borderColor: 'black',
borderRadius: 4,
height: 30,
width: 180,
paddingX: 2,
prepend: {
id: 'account-1',
type: 'icon',
props: {
alt: 'account icon',
icon: 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0nMjAnIGhlaWdodD0nMjAnIHZpZXdCb3g9JzAgMCAyMCAyMCcgZmlsbD0nbm9uZScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz48cGF0aCBkPSdNMyAxOUMzIDE0LjkxNzkgNS45NTY1MiAxMy40NTY1IDEwLjM5MTMgMTMuNDU2NU0xNy40MTMgMTlDMTcuNDEzIDE0LjkxNzkgMTQuNDU2NSAxMy40NTY1IDEwLjAyMTcgMTMuNDU2NScgc3Ryb2tlPScjODM5MkIxJyBzdHJva2UtbGluZWNhcD0ncm91bmQnIHN0cm9rZS1saW5lam9pbj0ncm91bmQnLz48Y2lyY2xlIGN4PScxMC4zOTI3JyBjeT0nNy4xNzM5MScgcj0nNC42NzM5MScgc3Ryb2tlPScjODM5MkIxJy8+PC9zdmc+IA==',
height: 20,
width: 20
}
},
component: {
id: 'account-2',
type: 'input',
props: {
name: 'account',
placeholder: 'Please input you account',
mode: 'text'
}
},
append: {
id: 'account-3',
type: 'icon',
props: {
alt: 'account icon',
link: 'https://google.com/search?q=account',
icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjODM5MkIxIiBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMHMxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMm0xIDE3aC0ydi0yaDJ6bTIuMDctNy43NWwtLjkuOTJDMTMuNDUgMTIuOSAxMyAxMy41IDEzIDE1aC0ydi0uNWMwLTEuMS40NS0yLjEgMS4xNy0yLjgzbDEuMjQtMS4yNmMuMzctLjM2LjU5LS44Ni41OS0xLjQxYzAtMS4xLS45LTItMi0ycy0yIC45LTIgMkg4YzAtMi4yMSAxLjc5LTQgNC00czQgMS43OSA0IDRjMCAuODgtLjM2IDEuNjgtLjkzIDIuMjUiLz48L3N2Zz4=',
height: 20,
width: 20
}
}
},
{
id: 'email-1',
borderWidth: 1,
borderColor: 'black',
borderRadius: 4,
height: 30,
width: 180,
paddingX: 2,
prepend: {
id: 'email-1',
type: 'icon',
props: {
alt: 'email icon',
icon: 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0nMjAnIGhlaWdodD0nMjAnIHZpZXdCb3g9JzAgMCAyMCAyMCcgZmlsbD0nbm9uZScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz48cGF0aCBkPSdNMi41IDUuNDc4MDNDMi41IDQuNjQ5NiAzLjE3MTU3IDMuOTc4MDMgNCAzLjk3ODAzSDE2QzE2LjgyODQgMy45NzgwMyAxNy41IDQuNjQ5NiAxNy41IDUuNDc4MDNWMTQuMTQ0N0MxNy41IDE0Ljk3MzEgMTYuODI4NCAxNS42NDQ3IDE2IDE1LjY0NDdINEMzLjE3MTU3IDE1LjY0NDcgMi41IDE0Ljk3MzEgMi41IDE0LjE0NDdWNS40NzgwM1onIHN0cm9rZT0nIzgzOTJCMScvPjxwYXRoIGQ9J00xNi45MDY4IDMuOTcyMjlMMTEuMzE0IDguOTg0NTlDMTAuNTU0NCA5LjY2NTMxIDkuNDA5MSA5LjY1OTQ3IDguNjU2NCA4Ljk3MTA2TDMuMTQwNjIgMy45MjYzOScgc3Ryb2tlPScjODM5MkIxJy8+PC9zdmc+IA==',
height: 20,
width: 20
}
},
component: {
id: 'email-2',
type: 'input',
props: {
name: 'email',
placeholder: 'Please input you email',
mode: 'email'
}
},
append: {
id: 'email-3',
type: 'icon',
props: {
alt: 'email icon',
link: 'https://google.com/search?q=email',
icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjODM5MkIxIiBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMHMxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMm0xIDE3aC0ydi0yaDJ6bTIuMDctNy43NWwtLjkuOTJDMTMuNDUgMTIuOSAxMyAxMy41IDEzIDE1aC0ydi0uNWMwLTEuMS40NS0yLjEgMS4xNy0yLjgzbDEuMjQtMS4yNmMuMzctLjM2LjU5LS44Ni41OS0xLjQxYzAtMS4xLS45LTItMi0ycy0yIC45LTIgMkg4YzAtMi4yMSAxLjc5LTQgNC00czQgMS43OSA0IDRjMCAuODgtLjM2IDEuNjgtLjkzIDIuMjUiLz48L3N2Zz4=',
height: 20,
width: 20
}
}
}
]
},
{
id: 'password-row',
gap: 10,
columns: [
{
id: 'column-2',
borderWidth: 1,
borderColor: 'black',
borderRadius: 4,
height: 30,
width: 375,
paddingX: 2,
focus: {
borderColor: 'red',
backgroundColor: 'yellow'
},
prepend: {
id: 'password-1',
type: 'icon',
props: {
alt: 'password icon',
icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIiBmaWxsPSJub25lIj4KPHBhdGggZD0iTTE1IDdINUMzLjg5NTQzIDcgMyA3Ljk4NTAxIDMgOS4yVjE1LjhDMyAxNy4wMTUgMy44OTU0MyAxOCA1IDE4SDE1QzE2LjEwNDUgMTggMTcgMTcuMDE1IDE3IDE1LjhWOS4yQzE3IDcuOTg1MDEgMTYuMTA0NSA3IDE1IDdaIiBzdHJva2U9IiM4MzkyQjEiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8cGF0aCBkPSJNNiA3VjUuMTI1QzYgNC4yOTYyIDYuNDIxNDMgMy41MDEzNCA3LjE3MTU3IDIuOTE1MjlDNy45MjE3MSAyLjMyOTI0IDguOTM5MDkgMiAxMCAyQzExLjA2MDkgMiAxMi4wNzgzIDIuMzI5MjQgMTIuODI4NSAyLjkxNTI5QzEzLjU3ODYgMy41MDEzNCAxNCA0LjI5NjIgMTQgNS4xMjVWNyIgc3Ryb2tlPSIjODM5MkIxIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGNpcmNsZSBjeD0iMTAiIGN5PSIxMiIgcj0iMSIgZmlsbD0iIzgzOTJCMSIvPgo8L3N2Zz4=',
height: 20,
width: 20
}
},
component: {
id: 'input-2',
type: 'input',
props: {
name: 'password',
placeholder: 'Please input you password',
mode: 'password'
}
},
append: {
id: 'password-3',
type: 'icon',
props: {
alt: 'password icon',
link: 'https://google.com/search?q=password',
icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjODM5MkIxIiBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMHMxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMm0xIDE3aC0ydi0yaDJ6bTIuMDctNy43NWwtLjkuOTJDMTMuNDUgMTIuOSAxMyAxMy41IDEzIDE1aC0ydi0uNWMwLTEuMS40NS0yLjEgMS4xNy0yLjgzbDEuMjQtMS4yNmMuMzctLjM2LjU5LS44Ni41OS0xLjQxYzAtMS4xLS45LTItMi0ycy0yIC45LTIgMkg4YzAtMi4yMSAxLjc5LTQgNC00czQgMS43OSA0IDRjMCAuODgtLjM2IDEuNjgtLjkzIDIuMjUiLz48L3N2Zz4=',
height: 20,
width: 20
}
}
}
]
},
{
id: 'login-row',
gap: 10,
columns: [
{
width: 200,
height: 30,
component: {
id: 'not-login-1',
type: 'checkbox',
props: {
name: 'not-login',
defaultChecked: true,
description: 'I not need login'
}
}
}
]
}
]}
/>
)
}
Render Result:
import React, { useMemo } from 'react'
import { FormProvider, Form as RawForm, useRegisterComponent, type FormProps } from '@gbyte/dynamic-form'
function CustomForm(props: FormProps) {
const CustomInput = useMemo(() => function CustomInput(props) {
return (
<div>
{props.name}
</div>
)
}, [])
const CustomCheckbox = useMemo(() => function CustomCheckbox(props) {
return (
<div>
{props.name}
</div>
)
}, [])
useRegisterComponent('input', CustomInput)
useRegisterComponent('checkbox', CustomCheckbox)
return (
<RawForm {...props} />
)
}
export default function Form(props: FormProps) {
return (
<FormProvider>
<CustomForm {...props} />
</FormProvider>
)
}
import React from 'react'
import { FormProvider, Form as RawForm, useRegisterComponent, type FormProps } from '../../src'
function CustomForm(props: FormProps) {
useRegisterComponent('input', props => {
return (
<div>
{props.name}
</div>
)
})
return (
<div>
<div>Page Header</div>
<hr />
<RawForm {...props} >
<details>
<summary>Goods List</summary>
<ul>
<li><span>goods-1</span> <span>price<i>$1</i></span></li>
</ul>
</details>
<div>
<hr />
<details>
<summary>user info</summary>
<div>
xxxx,
xxxx,
xxxx
</div>
</details>
<RawForm.Placeholder />
<hr />
<details>
<summary>delivery tips</summary>
<div>
xxxx,
xxxx,
xxxx
</div>
</details>
</div>
</RawForm>
<hr />
<div>Page Footer</div>
</div>
)
}
export default function Form(props: FormProps) {
return (
<FormProvider>
<CustomForm {...props} />
</FormProvider>
)
}
MIT