Skip to main content

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:

  • DocumentPage from so-kit-ui to manage data loading, permissions, and form actions.
  • Tabs to display the modular workflow: General, Shareholders, and conditionally, Registration.
  • useParams to read the id and startOperation (e.g., new, view, review) from the URL.
  • useLibrary to set breadcrumbs for navigation context.

Full Example

company-form.jsx
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

  • DocumentPage is 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 startOperation value (e.g., new, view, review)
  • ignoreConfirmLeave is configured to prevent unsaved changes warnings in non-editable modes like view

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.

New Form with error

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.