Form Component
Form Component
Now that the individual tabs are complete, we can assemble them into the main Company Form component. This is the core interface used to create, view, and review company data.
Component Overview
The form uses the following:
DocumentPagefrom so-kit-ui to manage data loading, permissions, and form actions.Tabsto display the modular workflow: General, Shareholders, and conditionally, Registration.useParamsto read theidandstartOperation(e.g.,new,view,review) from the URL.useLibraryto set breadcrumbs for navigation context.
Full Example
import { useEffect } from 'react';
import { useParams } from 'react-router';
import { DocumentPage, Page404, Tabs, useLibrary } from 'so-kit-ui';
import config from '../../app-config.jsx';
import { basic_roles } from '../../library.jsx';
import General from './components/tabs/General.jsx';
import { actionConfig, fieldConfig } from './config.jsx';
import Registration from './components/tabs/Registration.jsx';
import Shareholders from './components/tabs/Shareholders.jsx';
const registration = {
title: 'Registration',
content: <Registration />,
errorIds: ['vatNumber', 'remark'],
criteria: 'sw',
};
const tabsData = [
{
title: 'General',
content: <General />,
errorIds: [
'companyName',
'legalForm',
'capital',
'employees',
'type',
'address.street',
'address.city',
'address.state',
'address.zip',
'website',
'phone',
'email',
],
criteria: 'eq',
},
{
title: 'Shareholders',
content: <Shareholders />,
errorIds: ['shareholders'],
criteria: 'sw',
},
];
export const CompanyForm = () => {
const { id, startOperation } = useParams();
const { setBreadcrumbs } = useLibrary();
const tabs = [...tabsData];
if (
startOperation !== 'new' &&
!tabs.some((tab) => tab.title === registration.title)
) {
tabs.push(registration);
}
useEffect(() => {
setBreadcrumbs([
{ name: 'bc.company' },
{ name: 'bc.search', href: '/search' },
{ name: 'bc.form' },
id ? { name: id, noTranslate: true } : undefined,
]);
}, [id, startOperation]);
if (!startOperation) {
return <Page404 />;
}
return (
<div className='me-auto w-full xl:max-w-[1280px] 2xl:max-w-[1536px]'>
<DocumentPage
scope='company'
paramId={id}
paramStartOperation={startOperation}
apiBase={config?.company?.apiBase}
apiUri={config?.company?.apiUri}
actionConfig={actionConfig}
fieldConfig={fieldConfig}
roles={basic_roles}
ignoreConfirmLeave={['view']}
>
<Tabs tabsData={tabs} />
</DocumentPage>
</div>
);
};
Key Notes
DocumentPageis responsible for:- Handling API interactions
- Managing form state and data binding
- Enforcing role-based and action-specific permissions
- Tabs are dynamically rendered based on the
startOperationvalue (e.g.,new,view,review) ignoreConfirmLeaveis configured to prevent unsaved changes warnings in non-editable modes likeview
What’s Next
Now that the Company Form is fully constructed and wired up, navigate to the New Company page to test the form in action.

Upon opening the page, you’ll likely see an error message at the top of the form. This is expected—since the backend (or mock server) is not yet running, the application cannot retrieve or submit data.
Another thing you might notice is that the form appears to pulse. This is intentional behavior, visually indicating that the form is in a loading state while awaiting a response from the backend.
In the next step, we’ll configure and launch the mock server so we can test our form with sample data in a fully functional development environment.