UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

798 lines (737 loc) 21.4 kB
--- title: 'FieldBlock' description: '`FieldBlock` is a reusable wrapper for building Field-components. It shows surrounding elements through properties from `FieldProps` like `label` and `error`.' version: 10.104.0 generatedAt: 2026-04-17T18:46:12.712Z checksum: 090b7d977ba4be5e2c4c04d199a30a4048416c59f443a56985df2f80629d9c40 --- # FieldBlock ## Import ```tsx import { FieldBlock } from '@dnb/eufemia/extensions/forms' render(<FieldBlock />) ``` ## Description `FieldBlock` is a reusable wrapper [for building](/uilib/extensions/forms/create-component/) interactive [Field](/uilib/extensions/forms/feature-fields) components. It shows surrounding elements through properties from `FieldProps` like `label` and `error`, and ensure that spacing between different fields work as required when put into surrounding components like [Flex.Container](/uilib/layout/flex/container/) or [Form.Card](/uilib/extensions/forms/Form/Card/). ## Relevant links - [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/extensions/forms/create-component/FieldBlock) - [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock) It can also be used to group multiple inner FieldBlock components, composing status (error) messages together as one component. Check out the [Field.Composition](/uilib/extensions/forms/base-fields/Composition/) docs for that. ```tsx import { FieldBlock } from '@dnb/eufemia/extensions/forms' const YourFieldComponent = () => { return ( <FieldBlock forId="unique-id" label="A label" info="Info at the bottom" > <Input id="unique-id" /> </FieldBlock> ) } ``` More information about the usage can be found in the [create your own component](/uilib/extensions/forms/create-component/) section. ## Demos ### Label only (default layout) ```tsx render( <FieldBlock label="Label text">Input features goes here</FieldBlock> ) ``` ### With info ```tsx render( <FieldBlock label="Label text" info="For your information"> Input features goes here </FieldBlock> ) ``` ### Label size ```tsx render( <Form.Handler> <Flex.Stack> <Form.MainHeading>Heading</Form.MainHeading> <FieldBlock label="Legend with medium heading size" labelSize="medium" > <Field.String label="Label with a long text that goes beyond the field" width="medium" /> </FieldBlock> </Flex.Stack> </Form.Handler> ) ``` ### Horizontal layout ```tsx render( <FieldBlock label="Label text" layout="horizontal"> Input features goes here </FieldBlock> ) ``` ### Horizontal layout with info ```tsx render( <FieldBlock label="Label text" layout="horizontal" info="For your information" > Input features goes here </FieldBlock> ) ``` ### With label and label description (vertical only) ```tsx render( <FieldBlock label="Label text" labelDescription="Description text"> Input features goes here </FieldBlock> ) ``` ### With label description (vertical only) ```tsx render( <FieldBlock labelDescription="Description text"> Input features goes here </FieldBlock> ) ``` ### Responsive forms ```tsx render( <FieldBlock label="Label"> <Flex.Container> <Flex.Item size={{ small: 12, large: 'auto', }} > <Field.Name.First path="/firstName" width="medium" minLength={2} /> </Flex.Item> <Flex.Item size={{ small: 12, large: 'auto', }} > <Field.Name.Last path="/lastName" width="medium" required /> </Flex.Item> <Flex.Item size={{ small: 12, large: 'auto', }} > <FieldBlock width="large"> <Slider min={1900} max={new Date().getFullYear()} step={1} value={2010} label="Birth year" label_direction="vertical" tooltip alwaysShowTooltip /> </FieldBlock> </Flex.Item> </Flex.Container> </FieldBlock> ) ``` ### Combine error messages Error messages from all fields inside the FieldBlock are combined as one message below the whole block ```tsx render( <Field.Composition> <Field.Number width="small" label="Number" value={99} minimum={100} validateInitially /> <Field.String width="medium" label="Text" value="Text" minLength={5} validateInitially /> </Field.Composition> ) ``` ### Status position above Shows warning and info visually above the field by using `statusPosition="above"`. ```tsx render( <Field.String label="Field with status above" warning="Warning message" info="Info message" statusPosition="above" /> ) ``` ### Inline help button (vertical only) ```tsx render( <Flex.Stack> <Field.String label="Ønsket lånebeløp" help={{ title: 'Hva betyr lånebeløp?', content: ( <> Dette er hvor mye du har tenkt å låne{' '} <Anchor href="#test">totalt</Anchor>. </> ), }} onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> <Field.String label="Ønsket lånebeløp" multiline rows={3} help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Flex.Stack> ) ``` ### Inline help button (with label and label description) ```tsx render( <Flex.Stack> <Field.String label="Ønsket lånebeløp" labelDescription="Description Nisi ad ullamco ut anim proident sint eiusmod." help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> <Field.String label="Ønsket lånebeløp" labelDescription="Description" multiline rows={3} help={{ open: true, title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Flex.Stack> ) ``` ### Inline help button (with label description) ```tsx render( <Flex.Stack> <Field.String labelDescription="Description Nisi ad ullamco ut anim proident sint eiusmod." help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> <Field.String labelDescription="Description" multiline rows={3} help={{ open: true, title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Flex.Stack> ) ``` ### Inline help button (vertical label description) ```tsx render( <Form.Card> <Field.String label="Ønsket lånebeløp" labelDescription="Description" help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> <Field.String label="Ønsket lånebeløp" labelDescription="Description" multiline rows={3} help={{ open: true, title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Form.Card> ) ``` ### Inline help button (horizontal label) ```tsx render( <Form.Card> <Field.String label="Ønsket lånebeløp" layout="horizontal" help={{ open: true, title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} info="Info message" onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> <Field.String label="Ønsket lånebeløp" layout="horizontal" layoutOptions={{ width: '8rem', }} help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} info="Info message" /> <Field.String label="Ønsket lånebeløp" layout="horizontal" layoutOptions={{ width: '8rem', }} multiline rows={3} help={{ title: 'Hva betyr lånebeløp?', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} info="Info message" /> </Form.Card> ) ``` ### Inline help button (composition fields) ```tsx render( <Form.Card> <Field.Composition label="Field.Composition" width="large"> <Field.String width="medium" label="Label" help={{ title: 'Hva betyr lånebeløp? ', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> <Field.String width="stretch" label="Label" help={{ title: 'Hva betyr lånebeløp? ', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Field.Composition> <Field.PostalCodeAndCity help={{ title: 'Hva betyr lånebeløp? ', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> <Field.PhoneNumber help={{ open: true, title: 'Hva betyr lånebeløp? ', content: 'Dette er hvor mye du har tenkt å låne totalt.', }} /> </Form.Card> ) ``` ### Inline help button with HTML ```tsx render( <Flex.Stack> <Field.String label={<strong>Ønsket lånebeløp</strong>} labelDescription={ <span> Label description with a <Anchor href="/">Anchor</Anchor> </span> } help={{ open: true, title: <strong>Help title</strong>, content: ( <> Help content with a <Anchor href="/">Anchor</Anchor>. </> ), }} onChange={async () => { await new Promise((resolve) => setTimeout(resolve, 1000)) }} /> </Flex.Stack> ) ``` ### Widths ```tsx render( <Flex.Stack> <FieldBlock label="Default width (no width props). This label is long so we can validate that the label can be longer."> <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Small (affects outer block element)." width="small"> <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Medium (affects outer block element)." width="medium" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Large (affects outer block element)." width="large"> <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Custom (affects outer block element)." width="8rem"> <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Stretch (affects outer block element). This label is long so we can validate that the label also stretches full width." width="stretch" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Small (affects contents only). This label is long so we can validate that the label can be longer." contentWidth="small" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Medium (affects contents only). This label is long so we can validate that the label can be longer." contentWidth="medium" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Large (affects contents only). This label is long so we can validate that the label can be longer." contentWidth="large" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Custom (affects contents only). This label is long so we can validate that the label can be longer." contentWidth="8rem" > <TestElement>Contents</TestElement> </FieldBlock> <FieldBlock label="Stretch (affects contents only). This label is long so we can validate that the label can be longer." contentWidth="stretch" > <TestElement>Contents</TestElement> </FieldBlock> <Flex.Horizontal gap={false}> <FieldBlock width="stretch" style={{ backgroundColor: 'var(--color-mint-green)', }} > Left content </FieldBlock> <FieldBlock width="stretch" style={{ backgroundColor: 'var(--color-pistachio)', }} > Right content </FieldBlock> </Flex.Horizontal> </Flex.Stack> ) ``` ```tsx render( <FieldBlock layout="horizontal" composition width="large"> <Field.String label="Foo" width="medium" /> <Field.String label="Bar" width="medium" /> </FieldBlock> ) ``` ```tsx render( <Flex.Stack> <Form.Card> <Form.SubHeading>Breaking word with 61 characters</Form.SubHeading> <FieldBlock label={sixtyOneChars}>value</FieldBlock> <FieldBlock label={sixtyOneChars} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> <Form.Card> <Form.SubHeading> Breaking a sentence of 61 characters that include a space </Form.SubHeading> <FieldBlock label={sixtyOneCharsIncludingASpace}>value</FieldBlock> <FieldBlock label={sixtyOneCharsIncludingASpace} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> <Form.Card> <Form.SubHeading>Help button should not wrap alone</Form.SubHeading> <FieldBlock label={fiftyEightCharsIncludingASpace} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> </Flex.Stack> ) ``` ```tsx render( <Flex.Stack> <Form.Card> <Form.SubHeading>Breaking word with 68 characters</Form.SubHeading> <FieldBlock labelDescription={sixtyEightChars}>value</FieldBlock> <FieldBlock labelDescription={sixtyEightChars} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> <Form.Card> <Form.SubHeading> Breaking a sentence of 68 characters that include a space </Form.SubHeading> <FieldBlock labelDescription={sixtyEightCharsIncludingASpace}> value </FieldBlock> <FieldBlock labelDescription={sixtyEightCharsIncludingASpace} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> <Form.Card> <Form.SubHeading>Help button should not wrap alone</Form.SubHeading> <FieldBlock labelDescription={sixtyFiveCharsIncludingASpace} help={{ title: 'Help title', content: 'Help content', }} > value </FieldBlock> </Form.Card> </Flex.Stack> ) ``` ## Properties ```json { "props": { "label": { "doc": "Label text displayed above the field. Most fields already have a default label, so check the field translations for an existing label entry. Only set `label` when you need to override the default.", "type": "string", "status": "optional" }, "labelDescription": { "doc": "A more discreet text displayed beside the label (i.e for \"(optional)\").", "type": "string", "status": "optional" }, "labelDescriptionInline": { "doc": "If true, the `labelDescription` will be displayed on the same line as the label.", "type": "boolean", "status": "optional" }, "labelSrOnly": { "doc": "Use `true` to make the label only readable by screen readers.", "type": "boolean", "status": "optional" }, "labelSize": { "doc": "Define one of the following [heading sizes](/uilib/elements/heading/): `medium` or `large`.", "type": ["string", "false"], "status": "optional" }, "help": { "doc": "Provide help content for the field using `title` and `content` as a string or React.Node. Additionally, you can set `open` to `true` to display the inline help, set the `breakout` property to `false` to disable the breakout of the inline help content, set `outset` to `false` to display the help text inline (inset) instead of the default outset behavior, or use `renderAs` set to `dialog` to render the content in a [Dialog](/uilib/components/dialog/) (recommended for larger amounts of content).", "type": "object", "status": "optional" }, "hideHelpButton": { "doc": "Set `true` when you render the inline help button outside the label (e.g. inside a checkbox suffix) so FieldBlock skips drawing the default label help button.", "type": "boolean", "status": "optional" }, "statusPosition": { "doc": "Controls where status messages (`error`, `warning`, `info`) are visually shown. Use `below` (default) or `above`.", "type": ["\"below\"", "\"above\""], "status": "optional" }, "layout": { "doc": "Layout for the label and input. Can be `horizontal` or `vertical`.", "type": "string", "status": "optional" }, "layoutOptions": { "doc": "Use this to set additional options for the `horizontal` layout. E.g. `{ width: \"medium\" }`. You can also use a custom width `{number}rem`. Instead of a width, you can use a min/max width. E.g. `{ minWidth: \"6rem\", maxWidth: \"12rem\" }`.", "type": "object", "status": "optional" }, "width": { "doc": "Will set the width for the whole block. Use `small`, `medium`, `large` for predefined standard widths. You can also set a custom width `{number}rem` or use `stretch` or `false`.", "type": ["string", "false"], "status": "optional" }, "contentWidth": { "doc": "Will set the width for its contents. Use `small`, `medium`, `large` for predefined standard widths. You can also set a custom width `{number}rem` or use `stretch` or `false`.", "type": ["string", "false"], "status": "optional" }, "[Space](/uilib/layout/space/properties)": { "doc": "Spacing properties like `top` or `bottom` are supported.", "type": ["string", "object"], "status": "optional" }, "labelHeight": { "doc": "Defines the height of an component (size prop), so the label can be aligned correctly. Can be `default`, `small`, `medium`, `large`.", "type": "string", "status": "optional" }, "asFieldset": { "doc": "Use `true` when you have several form elements. This way a `fieldset` with a `legend` is used.", "type": "boolean", "status": "optional" }, "align": { "doc": "`center` or `bottom` for aligning the contents vertically. Defaults to `bottom`.", "type": ["string", "false"], "status": "optional" }, "disableStatusSummary": { "doc": "Use `true` to disable the error summary.", "type": "boolean", "status": "optional" }, "composition": { "doc": "Use `true` for when you have more than one field wrapped.", "type": "true", "status": "optional" }, "disabled": { "doc": "Set `true` to make the inner [FormLabel](/uilib/components/form-label/) behave as disabled.", "type": "boolean", "status": "optional" } } } ``` ## Translations ```json { "locales": ["da-DK", "en-GB", "nb-NO", "sv-SE"], "entries": { "Field.errorPattern": { "nb-NO": "Du må skrive inn en gyldig verdi.", "en-GB": "You must enter a valid value.", "sv-SE": "Du måste ange ett giltigt värde.", "da-DK": "Du skal indtaste en gyldig værdi." }, "Field.errorRequired": { "nb-NO": "Dette feltet må fylles ut.", "en-GB": "This field is required.", "sv-SE": "Detta fält måste fyllas i.", "da-DK": "Dette felt skal udfyldes." }, "Field.errorSummary": { "nb-NO": "Feil som må rettes:", "en-GB": "Please correct the following errors:", "sv-SE": "Fel som måste åtgärdas:", "da-DK": "Felter der skal rettes:" }, "Field.errorSummaryTitle": { "nb-NO": "Feil som må rettes", "en-GB": "Please correct the following errors", "sv-SE": "Fel som måste åtgärdas", "da-DK": "Felter der skal rettes" }, "Field.optionalLabelSuffix": { "nb-NO": "(valgfritt)", "en-GB": "(optional)", "sv-SE": "(valfritt)", "da-DK": "(valgfrit)" }, "Field.stateSummary": { "nb-NO": "Oppsummering:", "en-GB": "Summary:", "sv-SE": "Sammanfattning:", "da-DK": "Oversigt:" } } } ```