Skip to content

Description

Forms is reusable components for data input, data display and surrounding layout for simplified user interface creation in React, built on top of base Eufemia components.

The goal of the Forms extension is to make it easy to build forms and other data input features in DNB applications built with React.

The components constitute flexible building blocks that can be used individually, or together for a more practical data flow. They must also be easy to combine with components from other sources and local functionality in the individual application.

Data driven and loosely coupled

The components in Forms are data-driven. This means that they are built on the premises of the source data.

A form in a web application usually consists of two "steps". Data in, preferably from a database or a default data set to be distributed in fields on the screen, and data out, where what the user has typed or selected in the components must be collected in a corresponding data set before it is stored or sent to an API.

How to use

import '@dnb/eufemia/extensions/forms/style'
import {
Field,
Value,
Layout,
DataContext,
StepsLayout,
...
} from '@dnb/eufemia/extensions/forms'

JSON support

Some of the internal logic requires support for importing JSON files. Meta frameworks do often support this by default.

Demos

Base field components

Base field components are targeting the data type they produce. They can receive values and change handlers directly by props.

<Field.String
label="Text field"
value="Lorem Ipsum"
onChange={(value) => console.log('onChange', value)}
/>
<Field.Number
label="Number Field"
value={789}
onChange={(value) => console.log('onChange', value)}
/>
<Field.Boolean
label="Boolean Field"
value={true}
onChange={(value) => console.log('onChange', value)}
/>

Feature fields

Feature fields build on top of base field components and provide standard props for simplified form implementations.

<Field.FirstName value="John" />
<Field.LastName value="Smith" />
<Field.NationalIdentityNumber value="20058512345" />
<Field.Email value="john@smith.email" />
<Field.PhoneNumber value="+47 98765432" />

Layout components

Wrapping inputs in layout components provide the standard design without the need for local styles.

Profile

Name


More information



<Layout.Section>
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Layout.SubHeading>Name</Layout.SubHeading>
<Field.FirstName value="John" />
<Field.LastName value="Smith" />
</Layout.Card>
<Layout.Card stack>
<Layout.SubHeading>More information</Layout.SubHeading>
<Field.NationalIdentityNumber value="20058512345" />
<Field.Email value="john@smith.email" />
<Field.PhoneNumber value="+47 98765432" />
</Layout.Card>
</Layout.Section>

Using DataContextProvider

Wrapping fields with a DataContextProvider component lets them read and write data to one common data set, and have input and output of data in one place instead of connecting to every single field component.

Profile






<DataContext.Provider
data={{
firstName: 'John',
lastName: 'Smith',
ssn: '20058512345',
email: 'john@smith.email',
phone: '+47 98765432',
}}
onChange={(data) => console.log('onChange', data)}
onPathChange={(path, value) => console.log('onPathChange', path, value)}
onSubmit={(data) => console.log('onSubmit', data)}
>
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Field.FirstName path="/firstName" />
<Field.LastName path="/lastName" />
<Field.NationalIdentityNumber path="/ssn" />
<Field.Email path="/email" />
<Field.PhoneNumber path="/phone" />
<Layout.ButtonRow>
<DataContext.SubmitButton />
</Layout.ButtonRow>
</Layout.Card>
</DataContext.Provider>

Visibility based on data

Some fields are displayed when data fill specific requirements.

Profile

Name


<DataContext.Provider
data={{
firstName: undefined,
lastName: 'Smith',
advanced: false,
ssn: '123',
email: '@smith.email',
phone: '+47 98765432',
}}
onChange={(data) => console.log('onChange', data)}
onPathChange={(path, value) => console.log('onPathChange', path, value)}
onSubmit={(data) => console.log('onSubmit', data)}
>
<Layout.Section>
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Layout.SubHeading>Name</Layout.SubHeading>
<Field.FirstName path="/firstName" />
<Field.LastName path="/lastName" />
</Layout.Card>
</Layout.Section>
<Field.Boolean
path="/advanced"
variant="checkbox-button"
label="More fields"
/>
<Visibility pathTrue="/advanced">
<Layout.Section>
<Layout.Card stack>
<Layout.SubHeading>More information</Layout.SubHeading>
<Field.NationalIdentityNumber value="20058512345" />
<Field.Email value="john@smith.email" />
<Field.PhoneNumber value="+47 98765432" />
</Layout.Card>
</Layout.Section>
</Visibility>
</DataContext.Provider>

Validation

Here are some examples of validation properties of field components.

Profile





<DataContext.Provider
data={{
firstName: undefined,
lastName: 'Smith',
ssn: '123',
email: '@smith.email',
phone: '+47 98765432',
}}
onChange={(data) => console.log('onChange', data)}
onPathChange={(path, value) => console.log('onPathChange', path, value)}
onSubmit={(data) => console.log('onSubmit', data)}
>
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Field.FirstName path="/firstName" required />
<Field.LastName path="/lastName" required />
<Field.NationalIdentityNumber path="/ssn" validateInitially />
<Field.Email path="/email" validateInitially />
<Field.PhoneNumber path="/phone" validateInitially />
</Layout.Card>
</DataContext.Provider>

With steps

Some fields are displayed when data fill specific requirements.

Profile

Name


<DataContext.Provider
data={{
firstName: undefined,
lastName: 'Smith',
advanced: false,
ssn: '123',
email: '@smith.email',
phone: '+47 98765432',
}}
onChange={(data) => console.log('onChange', data)}
onPathChange={(path, value) => console.log('onPathChange', path, value)}
onSubmit={(data) => console.log('onSubmit', data)}
>
<StepsLayout>
<StepsLayout.Step title="Name">
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Layout.SubHeading>Name</Layout.SubHeading>
<Field.FirstName path="/firstName" required />
<Field.LastName path="/lastName" required />
</Layout.Card>
<Layout.ButtonRow>
<StepsLayout.NextButton />
</Layout.ButtonRow>
</StepsLayout.Step>
<StepsLayout.Step title="More information">
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Layout.SubHeading>More information</Layout.SubHeading>
<Field.NationalIdentityNumber path="/ssn" />
<Field.Email path="/email" />
<Field.PhoneNumber path="/phone" />
</Layout.Card>
<Layout.ButtonRow>
<StepsLayout.PreviousButton />
<StepsLayout.NextButton />
</Layout.ButtonRow>
</StepsLayout.Step>
<StepsLayout.Step title="Summary">
<Layout.MainHeading>Profile</Layout.MainHeading>
<Layout.Card stack>
<Layout.FlexContainer direction="row">
<Value.FirstName path="/firstName" />
<Value.LastName path="/lastName" />
</Layout.FlexContainer>
<Value.NationalIdentityNumber path="/ssn" />
<Value.Email path="/email" />
<Value.PhoneNumber path="/phone" />
</Layout.Card>
<Layout.ButtonRow>
<StepsLayout.PreviousButton />
<DataContext.SubmitButton />
</Layout.ButtonRow>
</StepsLayout.Step>
</StepsLayout>
</DataContext.Provider>