diff --git a/package.json b/package.json
index 648453f4953b..33c50776c7ee 100644
--- a/package.json
+++ b/package.json
@@ -95,4 +95,4 @@
"packages/website",
"packages/create-package"
]
-}
+}
\ No newline at end of file
diff --git a/packages/main/src/DatePicker.ts b/packages/main/src/DatePicker.ts
index cb3804bbe018..d110fa52c5c2 100644
--- a/packages/main/src/DatePicker.ts
+++ b/packages/main/src/DatePicker.ts
@@ -326,7 +326,7 @@ class DatePicker extends DateComponentBase implements IFormElement {
* Defines the open or closed state of the popover.
* @public
* @default false
- * @since 2.0
+ * @since 2.0.0
*/
@property({ type: Boolean })
open!: boolean;
diff --git a/packages/main/src/Form.hbs b/packages/main/src/Form.hbs
new file mode 100644
index 000000000000..4da5bc003771
--- /dev/null
+++ b/packages/main/src/Form.hbs
@@ -0,0 +1,35 @@
+
\ No newline at end of file
diff --git a/packages/main/src/Form.ts b/packages/main/src/Form.ts
new file mode 100644
index 000000000000..00625b072c4e
--- /dev/null
+++ b/packages/main/src/Form.ts
@@ -0,0 +1,456 @@
+import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
+import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
+import property from "@ui5/webcomponents-base/dist/decorators/property.js";
+import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
+import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
+import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
+
+// Template
+import FormTemplate from "./generated/templates/FormTemplate.lit.js";
+
+// Styles
+import FormCss from "./generated/themes/Form.css.js";
+
+import Title from "./Title.js";
+import FormItemSpacing from "./types/FormItemSpacing.js";
+import type FormGroup from "./FormGroup.js";
+
+const additionalStylesMap = new Map();
+
+const StepColumn = {
+ "S": 1,
+ "M": 2,
+ "L": 3,
+ "XL": 6,
+};
+
+interface IFormItem extends HTMLElement {
+ labelSpan: string
+ itemSpacing: `${FormItemSpacing}`;
+ readonly isGroup: boolean;
+ colsXl?: number;
+ colsL?: number;
+ colsM?: number;
+ colsS?: number;
+ columnSpan?: number;
+}
+
+type GroupItemsInfo = {
+ groupItem: IFormItem,
+ classes: string,
+ items: Array,
+}
+
+type ItemsInfo = {
+ item: IFormItem,
+ classes: string,
+}
+
+/**
+ * @class
+ *
+ * ### Overview
+ *
+ * The Form is a layout component that arranges labels and form fields (like input fields) pairs
+ * into a specific number of columns.
+ *
+ * ### Structure
+ *
+ * - **Form** (`ui5-form`) is the top-level container component, responsible for the content layout and responsiveness.
+ * - **FormGroup** (`ui5-form-group`) enables the grouping of the Form content.
+ * - **FormItem** (`ui5-form-item`) is a pair of label and form fields and can be used directly in a Form, or as part of a FormGroup.
+ *
+ * The simplest Form (`ui5-form`) consists of a header area on top,
+ * displaying a header text (see the `headingText` property) and content below - an arbitrary number of FormItems (ui5-form-item),
+ * representing the pairs of label and form fields.
+ *
+ * And, there is also "grouping" available to assist the implementation of richer UIs.
+ * This is enabled by the FormGroup (`ui5-form-group`) component.
+ * In this case, the Form is structured into FormGroups and each FormGroup consists of FormItems.
+ *
+ * ### Responsiveness
+ *
+ * The Form component reacts and changes its layout on predefined breakpoints.
+ * Depending on its size, the Form content (FormGroups and FormItems) gets divided into one or more columns as follows:
+ * - **S** (< 600px) – 1 column is recommended (default: 1)
+ * - **M** (600px - 1022px) – up to 2 columns are recommended (default: 1)
+ * - **L** (1023px - 1439px) - up to 3 columns are recommended (default: 2)
+ * - **XL** (> 1439px) – up to 6 columns are recommended (default: 2)
+ *
+ * To change the layout, use the `layout` property - f.e. layout="S1 M2 L3 XL6".
+ *
+ * ### Groups
+ *
+ * To make better use of screen space, there is built-in logic to determine how many columns should a FormGroup occupy.
+ *
+ * - **Example #1** (perfect match):
+ * 4 columns and 4 groups: each group will use 1 column.
+ *
+ * - **Example #2** (balanced distribution):
+ * 4 columns and 2 groups: each group will use 2 columns.
+ * 6 columns and 2 groups: each group will use 3 columns.
+ *
+ * - **Example #3** (unbalanced distribution):
+ * 3 columns and 2 groups: the larger one will use 2 columns, the smaller 1 column.
+ * 5 columns and 3 groups: two of the groups will use 2 columns each, the smallest 1 column.
+ *
+ * **Note:** The size of a group element is determined by the number of FormItems assigned to it.
+ * In the case of equality, the first in the DOM will use more columns, and the last - fewer columns.
+ *
+ * - **Example #4** (more groups than columns):
+ * 3 columns and 4 groups: each FormGroup uses only 1 column, the last FormGroup will wrap on the second row.
+ *
+ * ### Groups Column Span
+ *
+ * To influence the built-in group distribution, described in the previous section,
+ * you can use the FormGroup's `columnSpan` property, that defines how many columns the group should expand to.
+ *
+ * ### Items Column Span
+ *
+ * FormItem's columnSpan property defines how many columns the form item should expand to inside a form group or the form.
+ *
+ * ### Items Label Span
+ *
+ * The placement of the labels depends on the size of the used column.
+ * If there is enough space, the labels are next to their associated fields, otherwise - above the fields.
+ * By default, the labels take 4/12 of the FormItem, leaving 8/12 parts to associated fields.
+ * You can control what space the labels should take via the `labelSpan` property.
+ *
+ * **For example:** To always place the labels on top set: `labelSpan="S12 M12 L12 XL12"` property.
+ *
+ * ### ES6 Module Import
+ *
+ * - import @ui5/webcomponents/dist/Form.js";
+ * - import @ui5/webcomponents/dist/FormGroup.js";
+ * - import @ui5/webcomponents/dist/FormItem.js";
+ *
+ * @csspart header - Used to style the wrapper of the header.
+ * @csspart layout - Used to style the element defining the form column layout.
+ * @csspart column - Used to style a single column of the form column layout.
+ *
+ * @public
+ * @since 2.0.0
+ */
+@customElement({
+ tag: "ui5-form",
+ renderer: litRender,
+ styles: FormCss,
+ template: FormTemplate,
+ dependencies: [Title],
+})
+class Form extends UI5Element {
+ /**
+ * Defines the number of columns to distribute the form content by breakpoint.
+ *
+ * Supported values:
+ * - `S` - 1 column by default (1 column is recommended)
+ * - `M` - 1 column by default (up to 2 columns are recommended)
+ * - `L` - 2 columns by default (up to 3 columns are recommended)
+ * - `XL` - 2 columns by default (up to 6 columns are recommended)
+ *
+ * @default "S1 M1 L2 XL2"
+ * @public
+ */
+ @property({ type: String, defaultValue: "S1 M1 L2 XL2" })
+ layout!: string;
+
+ /**
+ * Defines the width proportion of the labels and fields of a FormItem by breakpoint.
+ *
+ * By default, the labels take 4/12 (or 1/3) of the form item in M,L and XL sizes,
+ * and 12/12 in S size, e.g in S the label is on top of its associated field.
+ *
+ * The supported values are between 1 and 12. Greater the number, more space the label will use.
+ *
+ * **Note:** If "12" is set, the label will be displayed on top of its assosiated field.
+ * @default "S12 M4 L4 XL4"
+ * @public
+ */
+ @property({ type: String, defaultValue: "S12 M4 L4 XL4" })
+ labelSpan!: string;
+
+ /**
+ * Defines the header text of the component.
+ *
+ * **Note:** The property gets overridden by the `header` slot.
+ *
+ * @default ""
+ * @public
+ */
+ @property()
+ headerText!: string;
+
+ /**
+ * Defines the vertical spacing between form items.
+ *
+ * **Note:** If the Form is meant to be switched between "non-edit" and "edit" modes,
+ * we recommend using "Large" item spacing in "non-edit" mode, and "Normal" - for "edit" mode,
+ * to avoid "jumping" effect, caused by the hight difference between texts in "non-edit" mode and the input fields in "edit" mode.
+ *
+ * @default "Normal"
+ * @public
+ */
+ @property({ type: FormItemSpacing, defaultValue: FormItemSpacing.Normal })
+ itemSpacing!: `${FormItemSpacing}`;
+
+ /**
+ * Defines the component header area.
+ *
+ * **Note:** When a `header` is provided, the `headerText` property is ignored.
+ * @public
+ */
+ @slot({ type: HTMLElement })
+ header!: Array;
+
+ /**
+ * Defines the component content - FormGroups or FormItems.
+ *
+ * **Note:** Mixing FormGroups and standalone FormItems (not belonging to a group) is not supported.
+ * Either use FormGroups and make sure all FormItems are part of a FormGroup, or use just FormItems without any FormGroups.
+ * @public
+ */
+ @slot({
+ type: HTMLElement,
+ "default": true,
+ individualSlots: true,
+ invalidateOnChildChange: true,
+ })
+ items!: Array;
+
+ /**
+ * @private
+ */
+ @property({ validator: Integer, defaultValue: 1 })
+ columnsS!: number;
+ @property({ validator: Integer, defaultValue: 12 })
+ labelSpanS!: number;
+
+ @property({ validator: Integer, defaultValue: 1 })
+ columnsM!: number;
+ @property({ validator: Integer, defaultValue: 4 })
+ labelSpanM!: number;
+
+ @property({ validator: Integer, defaultValue: 2 })
+ columnsL!: number;
+ @property({ validator: Integer, defaultValue: 4 })
+ labelSpanL!: number;
+
+ @property({ validator: Integer, defaultValue: 2 })
+ columnsXl!: number;
+ @property({ validator: Integer, defaultValue: 4 })
+ labelSpanXl!: number;
+
+ onBeforeRendering() {
+ // Parse the layout and set it to the FormGroups/FormItems.
+ this.setColumnLayout();
+
+ // Parse the labelSpan and set it to the FormGroups/FormItems.
+ this.setLabelSpan();
+
+ // Define how many columns a group should take.
+ this.setGroupsColSpan();
+ }
+
+ onAfterRendering() {
+ // Create additional CSS for number of columns that are not supported by default.
+ this.createAdditionalCSSStyleSheet();
+ }
+
+ setColumnLayout() {
+ const layoutArr = this.layout.split(" ");
+ layoutArr.forEach((breakpoint: string) => {
+ if (breakpoint.startsWith("S")) {
+ this.columnsS = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("M")) {
+ this.columnsM = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("L")) {
+ this.columnsL = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("XL")) {
+ this.columnsXl = parseInt(breakpoint.slice(2));
+ }
+ });
+ }
+
+ setLabelSpan() {
+ this.labelSpan.split(" ").forEach((breakpoint: string) => {
+ if (breakpoint.startsWith("S")) {
+ this.labelSpanS = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("M")) {
+ this.labelSpanM = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("L")) {
+ this.labelSpanL = parseInt(breakpoint.slice(1));
+ } else if (breakpoint.startsWith("XL")) {
+ this.labelSpanXl = parseInt(breakpoint.slice(2));
+ }
+ });
+
+ this.items.forEach((item: IFormItem) => {
+ item.labelSpan = this.labelSpan;
+ item.itemSpacing = this.itemSpacing;
+ });
+ }
+
+ setGroupsColSpan() {
+ if (!this.hasGroupItems) {
+ return;
+ }
+
+ const itemsCount = this.items.length;
+ const sortedItems = [...this.items].sort((itemA: IFormItem, itemB: IFormItem) => {
+ return (itemB as FormGroup)?.items.length - (itemA as FormGroup)?.items.length;
+ });
+
+ sortedItems.forEach((item: IFormItem, idx: number) => {
+ item.colsXl = this.getGroupsColSpan(this.columnsXl, itemsCount, idx, item);
+ item.colsL = this.getGroupsColSpan(this.columnsL, itemsCount, idx, item);
+ item.colsM = this.getGroupsColSpan(this.columnsM, itemsCount, idx, item);
+ item.colsS = this.getGroupsColSpan(this.columnsS, itemsCount, idx, item);
+ });
+ }
+
+ getGroupsColSpan(cols: number, groups: number, index: number, group: IFormItem): number {
+ // Case 0: column span is set from outside.
+ if (group.columnSpan) {
+ return group.columnSpan;
+ }
+
+ // CASE 1: The number of available columns match the number of groups, or only 1 column is available - each group takes 1 column.
+ // For example: 1 column - 1 group, 2 columns - 2 groups, 3 columns - 3 groups, 4columns - 4 groups
+ if (cols === 1 || cols <= groups) {
+ return 1;
+ }
+
+ // CASE 2: The number of available columns IS multiple of the number of groups.
+ // For example: 2 column - 1 group, 3 columns - 1 groups, 4 columns - 1 group, 4 columns - 2 groups
+ if (cols % groups === 0) {
+ return cols / groups;
+ }
+
+ // CASE 3: The number of available columns IS NOT multiple of the number of groups.
+ const MIN_COL_SPAN = 1;
+ const delta = cols - groups;
+
+ // 7 cols & 4 groups => 2, 2, 2, 1
+ if (delta <= groups) {
+ return index < delta ? MIN_COL_SPAN + 1 : MIN_COL_SPAN;
+ }
+
+ // 7 cols & 3 groups => 3, 2, 2
+ return index === 0 ? MIN_COL_SPAN + (delta - groups) + 1 : MIN_COL_SPAN + 1;
+ }
+
+ get hasGroupItems(): boolean {
+ return this.items.some((item: IFormItem) => item.isGroup);
+ }
+
+ get hasCustomHeader(): boolean {
+ return !!this.header.length;
+ }
+
+ get ariaLabelledByID(): string | undefined {
+ return this.hasCustomHeader ? undefined : `${this._id}-header-text`;
+ }
+
+ get groupItemsInfo(): Array {
+ return this.items.map((groupItem: IFormItem) => {
+ return {
+ groupItem,
+ classes: `ui5-form-column-spanL-${groupItem.colsL} ui5-form-column-spanXL-${groupItem.colsXl} ui5-form-column-spanM-${groupItem.colsM} ui5-form-column-spanS-${groupItem.colsS}`,
+ items: this.getItemsInfo((Array.from(groupItem.children) as Array)),
+ };
+ });
+ }
+
+ get itemsInfo(): Array {
+ return this.getItemsInfo();
+ }
+
+ getItemsInfo(items?: Array): Array {
+ return (items || this.items).map((item: IFormItem) => {
+ return {
+ item,
+ classes: item.columnSpan ? `ui5-form-item-span-${item.columnSpan}` : "",
+ };
+ });
+ }
+
+ createAdditionalCSSStyleSheet() {
+ [
+ { breakpoint: "S", columns: this.columnsS },
+ { breakpoint: "M", columns: this.columnsM },
+ { breakpoint: "L", columns: this.columnsL },
+ { breakpoint: "XL", columns: this.columnsXl },
+ ].forEach(step => {
+ const additionalStyle: string | undefined = this.getAdditionalCSS(step.breakpoint, step.columns);
+
+ if (additionalStyle) {
+ this.shadowRoot!.adoptedStyleSheets = [...this.shadowRoot!.adoptedStyleSheets, this.getCSSStyleSheet(additionalStyle)];
+ }
+ });
+ }
+
+ getAdditionalCSS(step: string, colsNumber: number): string | undefined {
+ if (StepColumn[step as keyof typeof StepColumn] >= colsNumber) {
+ return;
+ }
+
+ const key = `${step}-${colsNumber}`;
+
+ if (!additionalStylesMap.has(key)) {
+ let containerQuery;
+ let supporedColumnsNumber!: number;
+ let stepSpanCSS = "";
+ let cols = colsNumber;
+
+ if (step === "S") {
+ supporedColumnsNumber = StepColumn.S;
+ containerQuery = `@container (max-width: 599px) {`;
+ } else if (step === "M") {
+ supporedColumnsNumber = StepColumn.M;
+ containerQuery = `@container (width > 599px) and (width < 1024px) {`;
+ } else if (step === "L") {
+ supporedColumnsNumber = StepColumn.L;
+ containerQuery = `@container (width > 1023px) and (width < 1439px) {`;
+ } else if (step === "XL") {
+ containerQuery = `@container (min-width: 1440px) {`;
+ supporedColumnsNumber = StepColumn.XL;
+ }
+
+ while (cols > supporedColumnsNumber) {
+ stepSpanCSS += `
+ :host([columns-${step.toLocaleLowerCase()}="${cols}"]) .ui5-form-layout {
+ grid-template-columns: repeat(${cols}, 1fr);
+ }
+
+ .ui5-form-column-span${step}-${cols},
+ .ui5-form-item-span-${cols} {
+ grid-column: span ${cols};
+ }
+
+ .ui5-form-column-span${step}-${cols} .ui5-form-group-layout {
+ grid-template-columns: repeat(${cols}, 1fr);
+ }
+ `;
+ cols--;
+ }
+
+ const css = `${containerQuery}${stepSpanCSS}}`;
+ additionalStylesMap.set(key, css);
+ }
+
+ return additionalStylesMap.get(key)!;
+ }
+
+ getCSSStyleSheet(cssText: string): CSSStyleSheet {
+ const style = new CSSStyleSheet();
+ style.replaceSync(cssText);
+ return style;
+ }
+}
+
+Form.define();
+
+export default Form;
+export {
+ IFormItem,
+};
diff --git a/packages/main/src/FormGroup.ts b/packages/main/src/FormGroup.ts
new file mode 100644
index 000000000000..5616d913f263
--- /dev/null
+++ b/packages/main/src/FormGroup.ts
@@ -0,0 +1,105 @@
+import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
+import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
+import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
+import property from "@ui5/webcomponents-base/dist/decorators/property.js";
+import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
+
+import type FormItem from "./FormItem.js";
+import type { IFormItem } from "./Form.js";
+import FormItemSpacing from "./types/FormItemSpacing.js";
+
+/**
+ * @class
+ *
+ * ### Overview
+ *
+ * The FormGroup (ui5-form-group) represents a group inside the Form (ui5-form) component
+ * and it consists of FormItem (ui5-form-item) components.
+ *
+ * The layout of the FormGroup is mostly defined and controlled by the overarching Form (ui5-form) component.
+ * Still, one can influence the layout via the FormGroup's `columnSpan` property,
+ * that defines how many columns the group should expand to.
+ *
+ * ### Usage
+ *
+ * Тhe FormGroup (ui5-form-group) allows to split a Form into groups,
+ * e.g to group FormItems that logically belong together.
+ *
+ * ### ES6 Module Import
+ *
+ * - import @ui5/webcomponents/dist/FormGroup.js";
+ *
+ * @public
+ * @since 2.0.0
+ */
+@customElement("ui5-form-group")
+class FormGroup extends UI5Element implements IFormItem {
+ /**
+ * Defines header text of the component.
+ *
+ * @default ""
+ * @public
+ */
+ @property()
+ headerText!: string;
+
+ /**
+ * Defines column span of the component,
+ * e.g how many columns the group should span to.
+ *
+ * @default undefined
+ * @public
+ */
+ @property({ validator: Integer, defaultValue: undefined })
+ columnSpan?: number;
+
+ /**
+ * Defines the items of the component.
+ * @public
+ */
+ @slot({
+ type: HTMLElement,
+ "default": true,
+ })
+ items!: Array;
+
+ /**
+ * @private
+ */
+ @property({ validator: Integer, defaultValue: 1 })
+ colsS!: number;
+
+ @property({ validator: Integer, defaultValue: 1 })
+ colsM!: number;
+
+ @property({ validator: Integer, defaultValue: 1 })
+ colsL!: number;
+
+ @property({ validator: Integer, defaultValue: 1 })
+ colsXl!: number;
+
+ @property({ type: FormItemSpacing, defaultValue: FormItemSpacing.Normal })
+ itemSpacing!: `${FormItemSpacing}`;
+
+ @property({ type: String, defaultValue: "S12 M4 L4 XL4" })
+ labelSpan!: string;
+
+ onBeforeRendering() {
+ this.processFormItems();
+ }
+
+ processFormItems() {
+ this.items.forEach((item: FormItem) => {
+ item.labelSpan = this.labelSpan;
+ item.itemSpacing = this.itemSpacing;
+ });
+ }
+
+ get isGroup() {
+ return true;
+ }
+}
+
+FormGroup.define();
+
+export default FormGroup;
diff --git a/packages/main/src/FormItem.hbs b/packages/main/src/FormItem.hbs
new file mode 100644
index 000000000000..f38e5da27b20
--- /dev/null
+++ b/packages/main/src/FormItem.hbs
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/packages/main/src/FormItem.ts b/packages/main/src/FormItem.ts
new file mode 100644
index 000000000000..1a6b0f16831f
--- /dev/null
+++ b/packages/main/src/FormItem.ts
@@ -0,0 +1,100 @@
+import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
+import property from "@ui5/webcomponents-base/dist/decorators/property.js";
+import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
+import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
+import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
+import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
+
+// Template
+import FormItemTemplate from "./generated/templates/FormItemTemplate.lit.js";
+
+// Styles
+import FormItemCss from "./generated/themes/FormItem.css.js";
+
+import type { IFormItem } from "./Form.js";
+import FormItemSpacing from "./types/FormItemSpacing.js";
+
+/**
+ * @class
+ *
+ * ### Overview
+ *
+ * The FormItem (ui5-form-item) represents pair of a label and
+ * one or more components (text or text fields), associated to it.
+ *
+ * ### Usage
+ *
+ * The FormItem is being used in FormGroup (ui5-form-group) or directly in Form (ui5-form).
+ *
+ * ### ES6 Module Import
+ *
+ * - import @ui5/webcomponents/dist/FormItem.js";
+ *
+ * @csspart layout - Used to style the parent element of the label and content parts.
+ * @csspart label - Used to style the label part of the form item.
+ * @csspart content - Used to style the content part of the form item.
+ *
+ * @constructor
+ * @public
+ * @since 2.0.0
+ */
+@customElement({
+ tag: "ui5-form-item",
+ renderer: litRender,
+ styles: FormItemCss,
+ template: FormItemTemplate,
+})
+class FormItem extends UI5Element implements IFormItem {
+ /**
+ * Defines the column span of the component,
+ * e.g how many columns the component should span to.
+ *
+ * **Note:** The column span should be a number between 1 and the available columns of the FormGroup (when items are placed in a group)
+ * or the Form. The available columns can be affected by the FormGroup#columnSpan and/or the Form#layout.
+ * A number bigger than the available columns won't take effect.
+ *
+ * @default undefined
+ * @public
+ */
+ @property({ validator: Integer, defaultValue: undefined })
+ columnSpan?: number;
+
+ /**
+ * Defines the label of the component.
+ * @public
+ */
+ @slot()
+ labelContent!: Array;
+
+ /**
+ * Defines the content of the component,
+ * associated to `labelContent`.
+ * @public
+ */
+ @slot({
+ type: HTMLElement,
+ "default": true,
+ individualSlots: true,
+ })
+ content!: Array;
+
+ /**
+ * @private
+ */
+ @property({ type: String, defaultValue: "S12 M4 L4 XL4" })
+ labelSpan!: string;
+
+ /**
+ * @private
+ */
+ @property({ type: FormItemSpacing, defaultValue: FormItemSpacing.Normal })
+ itemSpacing!: `${FormItemSpacing}`;
+
+ get isGroup() {
+ return false;
+ }
+}
+
+FormItem.define();
+
+export default FormItem;
diff --git a/packages/main/src/ListItemGroup.ts b/packages/main/src/ListItemGroup.ts
index bfbfb56e76ed..73522c92aa34 100644
--- a/packages/main/src/ListItemGroup.ts
+++ b/packages/main/src/ListItemGroup.ts
@@ -26,7 +26,7 @@ import ListItemGroupHeader from "./ListItemGroupHeader.js";
* @constructor
* @extends UI5Element
* @public
- * @since 2.0
+ * @since 2.0.0
*/
@customElement({
tag: "ui5-li-group",
diff --git a/packages/main/src/Popup.ts b/packages/main/src/Popup.ts
index d1c2919f0c8b..ea8b296a3449 100644
--- a/packages/main/src/Popup.ts
+++ b/packages/main/src/Popup.ts
@@ -177,7 +177,7 @@ abstract class Popup extends UI5Element {
* Indicates whether initial focus should be prevented.
* @public
* @default false
- * @since 2.0
+ * @since 2.0.0
*/
@property({ type: Boolean })
preventInitialFocus!: boolean;
diff --git a/packages/main/src/Tag.ts b/packages/main/src/Tag.ts
index 31d257ae913f..b009abf510f5 100644
--- a/packages/main/src/Tag.ts
+++ b/packages/main/src/Tag.ts
@@ -134,7 +134,7 @@ class Tag extends UI5Element {
* Defines predefined size of the component.
* @default "S"
* @public
- * @since 2.0
+ * @since 2.0.0
*/
@property({ type: TagSize, defaultValue: TagSize.S })
size!: `${TagSize}`;
diff --git a/packages/main/src/Tokenizer.ts b/packages/main/src/Tokenizer.ts
index 6cac10cdf59f..956324a2ee35 100644
--- a/packages/main/src/Tokenizer.ts
+++ b/packages/main/src/Tokenizer.ts
@@ -128,8 +128,8 @@ enum ClipboardDataOperation {
*
* @constructor
* @extends sap.ui.webc.base.UI5Element
- * @since 2.0
* @public
+ * @since 2.0.0
*/
@customElement({
tag: "ui5-tokenizer",
diff --git a/packages/main/src/bundle.esm.ts b/packages/main/src/bundle.esm.ts
index 97a1b5bc9b6d..47ace49c7fb9 100644
--- a/packages/main/src/bundle.esm.ts
+++ b/packages/main/src/bundle.esm.ts
@@ -115,6 +115,9 @@ import DatePicker from "./DatePicker.js";
import DateRangePicker from "./DateRangePicker.js";
import DateTimePicker from "./DateTimePicker.js";
import Dialog from "./Dialog.js";
+import Form from "./Form.js";
+import FormItem from "./FormItem.js";
+import FormGroup from "./FormGroup.js";
import FileUploader from "./FileUploader.js";
import Icon from "./Icon.js";
import Input from "./Input.js";
diff --git a/packages/main/src/themes/Form.css b/packages/main/src/themes/Form.css
new file mode 100644
index 000000000000..28fd2c90948b
--- /dev/null
+++ b/packages/main/src/themes/Form.css
@@ -0,0 +1,50 @@
+@import "./FormLayout.css";
+@import "./FormLabelSpan.css";
+
+:host {
+ display: block;
+}
+
+.ui5-form-root {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--sapGroup_ContentBackground);
+ border-radius: 0.75rem;
+ container-type: inline-size;
+}
+
+.ui5-form-header {
+ display: flex;
+ height: 2.75rem;
+ align-items: center;
+ border-bottom: 1px solid var(--sapGroup_TitleBorderColor);
+ padding: 0 1rem 0 1rem;
+}
+
+.ui5-form-layout {
+ display: grid;
+ column-gap: 1rem;
+ row-gap: 0.125rem;
+ padding: 1rem 0.75rem;
+}
+
+.ui5-form-group-layout {
+ display: grid;
+ column-gap: 1rem;
+}
+
+.ui5-form-group-heading {
+ height: var(--_ui5-form-group-heading-height);
+ line-height: var(--_ui5-form-group-heading-height);
+ padding-inline-start: 0.25rem;
+}
+
+.ui5-form-column {
+ padding-top: 0.5rem;
+ padding-bottom: 1rem;
+ box-sizing: border-box;
+}
+
+::slotted([ui5-form-group]) {
+ display: contents;
+}
diff --git a/packages/main/src/themes/FormItem.css b/packages/main/src/themes/FormItem.css
new file mode 100644
index 000000000000..446eda5d6b96
--- /dev/null
+++ b/packages/main/src/themes/FormItem.css
@@ -0,0 +1,65 @@
+:host([column-span="1"]) {
+ grid-column: span 1;
+}
+
+:host([column-span="2"]) {
+ grid-column: span 2;
+}
+
+:host([column-span="3"]) {
+ grid-column: span 3;
+}
+
+:host([column-span="4"]) {
+ grid-column: span 4;
+}
+
+:host([column-span="5"]) {
+ grid-column: span 5;
+}
+:host([column-span="6"]) {
+ grid-column: span 6;
+}
+
+.ui5-form-item-root {
+ container-type: inline-size;
+ background-color: inherit;
+ color: inherit;
+}
+
+.ui5-form-item-layout {
+ display: grid;
+ grid-template-columns: var(--ui5-form-item-layout);
+ align-items: center;
+}
+
+.ui5-form-item-label {
+ padding: var(--ui5-form-item-label-padding);
+ padding-inline-end: var(--ui5-form-item-label-padding-end);
+ justify-self: var(--ui5-form-item-label-justify);
+}
+
+.ui5-form-item-content {
+ display: flex;
+ padding: 0 0.25rem;
+}
+
+.ui5-form-item-content-child {
+ padding-inline-end: 0.5rem;
+ box-sizing: border-box;
+ width: 100%;
+}
+
+:host([item-spacing="Large"]) .ui5-form-item-layout {
+ min-height: var(--_ui5_form_item_min_height);
+ padding-top: var(--_ui5_form_item_padding);
+ padding-bottom: var(--_ui5_form_item_padding);
+ box-sizing: border-box;
+}
+
+::slotted([ui5-input]) {
+ width: 100%;
+}
+::slotted([ui5-select]) {
+ width: 100%;
+}
\ No newline at end of file
diff --git a/packages/main/src/themes/FormLabelSpan.css b/packages/main/src/themes/FormLabelSpan.css
new file mode 100644
index 000000000000..bfbe6c150755
--- /dev/null
+++ b/packages/main/src/themes/FormLabelSpan.css
@@ -0,0 +1,267 @@
+/*
+* The Form's labels take 4 cells out 12 in M, L ans XL sizes,
+* and 12 cells (whole row) in S size.
+* The ratio can be changed trough the labelSpan property.
+*/
+
+/* S - 12 cells */
+@container (max-width: 600px) {
+ :host([label-span-s="1"]) .ui5-form-item,
+ :host([label-span-s="1"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span1);
+ }
+
+ :host([label-span-s="2"]) .ui5-form-item,
+ :host([label-span-s="2"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span2);
+ }
+
+ :host([label-span-s="3"]) .ui5-form-item,
+ :host([label-span-s="3"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span3);
+ }
+
+ :host([label-span-s="4"]) .ui5-form-item,
+ :host([label-span-s="4"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span4);
+ }
+
+ :host([label-span-s="5"]) .ui5-form-item,
+ :host([label-span-s="5"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span5);
+ }
+
+ :host([label-span-s="6"]) .ui5-form-item,
+ :host([label-span-s="6"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span6);
+ }
+
+ :host([label-span-s="7"]) .ui5-form-item,
+ :host([label-span-s="7"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span7);
+ }
+
+ :host([label-span-s="8"]) .ui5-form-item,
+ :host([label-span-s="8"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span8);
+ }
+
+ :host([label-span-s="9"]) .ui5-form-item,
+ :host([label-span-s="9"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span9);
+ }
+
+ :host([label-span-s="10"]) .ui5-form-item,
+ :host([label-span-s="10"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span10);
+ }
+
+ :host([label-span-s="11"]) .ui5-form-item,
+ :host([label-span-s="11"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span11);
+ }
+
+ :host(:not([label-span-s])) .ui5-form-item,
+ :host(:not([label-span-s])) .ui5-form-group,
+ :host([label-span-s="12"]) .ui5-form-item,
+ :host([label-span-s="12"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span12);
+ --ui5-form-item-label-justify: var(--ui5-form-item-label-justify-span12);
+ --ui5-form-item-label-padding: var(--ui5-form-item-label-padding-span12);
+ }
+}
+
+/* M - 4 cells by default, up to 12 cells */
+@container (width > 600px) and (width <= 1024px) {
+ :host([label-span-m="1"]) .ui5-form-item,
+ :host([label-span-m="1"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span1);
+ }
+
+ :host([label-span-m="2"]) .ui5-form-item,
+ :host([label-span-m="2"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span2);
+ }
+
+ :host([label-span-m="3"]) .ui5-form-item,
+ :host([label-span-m="3"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span3);
+ }
+
+ :host([label-span-m="4"]) .ui5-form-item,
+ :host([label-span-m="4"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span4);
+ }
+
+ :host([label-span-m="5"]) .ui5-form-item,
+ :host([label-span-m="5"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span5);
+ }
+
+ :host([label-span-m="6"]) .ui5-form-item,
+ :host([label-span-m="6"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span6);
+ }
+
+ :host([label-span-m="7"]) .ui5-form-item,
+ :host([label-span-m="7"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span7);
+ }
+
+ :host([label-span-m="8"]) .ui5-form-item,
+ :host([label-span-m="8"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span8);
+ }
+
+ :host([label-span-m="9"]) .ui5-form-item,
+ :host([label-span-m="9"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span9);
+ }
+
+ :host([label-span-m="10"]) .ui5-form-item,
+ :host([label-span-m="10"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span10);
+ }
+
+ :host([label-span-m="11"]) .ui5-form-item,
+ :host([label-span-m="11"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span11);
+ }
+
+ :host([label-span-m="12"]) .ui5-form-item,
+ :host([label-span-m="12"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span12);
+ --ui5-form-item-label-justify: var(--ui5-form-item-label-justify-span12);
+ --ui5-form-item-label-padding: var(--ui5-form-item-label-padding-span12);
+ }
+}
+
+/* L - 4 cells by default, up to 12 cells */
+@container (width > 1024px) and (width <= 1440px) {
+ :host([label-span-l="1"]) .ui5-form-item,
+ :host([label-span-l="1"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span1);
+ }
+
+ :host([label-span-l="2"]) .ui5-form-item,
+ :host([label-span-l="2"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span2);
+ }
+
+ :host([label-span-l="3"]) .ui5-form-item,
+ :host([label-span-l="3"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span3);
+ }
+
+ :host([label-span-l="4"]) .ui5-form-item,
+ :host([label-span-l="4"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span4);
+ }
+
+ :host([label-span-l="5"]) .ui5-form-item,
+ :host([label-span-l="5"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span5);
+ }
+
+ :host([label-span-l="6"]) .ui5-form-item,
+ :host([label-span-l="6"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span6);
+ }
+
+ :host([label-span-l="7"]) .ui5-form-item,
+ :host([label-span-l="7"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span7);
+ }
+
+ :host([label-span-l="8"]) .ui5-form-item,
+ :host([label-span-l="8"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span8);
+ }
+
+ :host([label-span-l="9"]) .ui5-form-item,
+ :host([label-span-l="9"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span9);
+ }
+
+ :host([label-span-l="10"]) .ui5-form-item,
+ :host([label-span-l="10"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span10);
+ }
+
+ :host([label-span-l="11"]) .ui5-form-item,
+ :host([label-span-l="11"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span11);
+ }
+
+ :host([label-span-l="12"]) .ui5-form-item,
+ :host([label-span-l="12"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span12);
+ --ui5-form-item-label-justify: var(--ui5-form-item-label-justify-span12);
+ --ui5-form-item-label-padding: var(--ui5-form-item-label-padding-span12);
+ }
+}
+
+/* XL - 4 cells by default, up to 12 cells */
+@container (min-width: 1441px) {
+ :host([label-span-xl="1"]) .ui5-form-item,
+ :host([label-span-xl="1"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span1);
+ }
+
+ :host([label-span-xl="2"]) .ui5-form-item,
+ :host([label-span-xl="2"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span2);
+ }
+
+ :host([label-span-xl="3"]) .ui5-form-item,
+ :host([label-span-xl="3"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span3);
+ }
+
+ :host([label-span-xl="4"]) .ui5-form-item,
+ :host([label-span-xl="4"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span4);
+ }
+
+ :host([label-span-xl="5"]) .ui5-form-item,
+ :host([label-span-xl="5"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span5);
+ }
+
+ :host([label-span-xl="6"]) .ui5-form-item,
+ :host([label-span-xl="6"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span6);
+ }
+
+ :host([label-span-xl="7"]) .ui5-form-item,
+ :host([label-span-xl="7"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span7);
+ }
+
+ :host([label-span-xl="8"]) .ui5-form-item,
+ :host([label-span-xl="8"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span8);
+ }
+
+ :host([label-span-xl="9"]) .ui5-form-item,
+ :host([label-span-xl="9"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span9);
+ }
+
+ :host([label-span-xl="10"]) .ui5-form-item,
+ :host([label-span-xl="10"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span10);
+ }
+
+ :host([label-span-xl="11"]) .ui5-form-item,
+ :host([label-span-xl="11"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span11);
+ }
+
+ :host([label-span-xl="12"]) .ui5-form-item,
+ :host([label-span-xl="12"]) .ui5-form-group {
+ --ui5-form-item-layout: var(--ui5-form-item-layout-span12);
+ --ui5-form-item-label-justify: var(--ui5-form-item-label-justify-span12);
+ --ui5-form-item-label-padding: var(--ui5-form-item-label-padding-span12);
+ }
+}
\ No newline at end of file
diff --git a/packages/main/src/themes/FormLayout.css b/packages/main/src/themes/FormLayout.css
new file mode 100644
index 000000000000..56b87013a9dc
--- /dev/null
+++ b/packages/main/src/themes/FormLayout.css
@@ -0,0 +1,159 @@
+/*
+* The Form layout is divided into one or more columns.
+* XL - max. 4 columns, L - max. 3 columns, M - max. 2 columns and S - 1 column.
+*/
+/*
+* S max-width: 600px - container padding 24px
+*/
+
+/* S - 1 column */
+@container (max-width: 600px) {
+ .ui5-form-layout {
+ grid-template-columns: 1fr;
+ }
+
+ ::slotted(*) {
+ justify-self: start;
+ }
+ ::slotted(:nth-child(2n)){
+ margin-bottom: 0.5rem;
+ }
+}
+
+/* M - 1 column by default, up to 2 columns */
+@container (width > 600px) and (width <= 1024px) {
+ .ui5-form-layout {
+ grid-template-columns: 1fr;
+ }
+ :host([columns-m="1"]) .ui5-form-layout {
+ grid-template-columns: 1fr;
+ }
+ :host([columns-m="2"]) .ui5-form-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .ui5-form-column-spanM-2 {
+ grid-column: span 2;
+ }
+
+ .ui5-form-column-spanM-2 .ui5-form-group-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+/* L - 2 columns by default, up to 3 columns */
+@container (width > 1024px) and (width <= 1440px) {
+
+ .ui5-form-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ .ui5-form-column {
+ grid-template-columns: 1fr;
+ }
+
+ :host([columns-l="1"]) .ui5-form-layout {
+ grid-template-columns: 1fr;
+ }
+ :host([columns-l="2"]) .ui5-form-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ :host([columns-l="3"]) .ui5-form-layout {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ .ui5-form-column-spanL-2 {
+ grid-column: span 2;
+ }
+ .ui5-form-column-spanL-2 .ui5-form-group-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .ui5-form-column-spanL-3 {
+ grid-column: span 3;
+ }
+ .ui5-form-column-spanL-3 .ui5-form-group-layout {
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+/* XL - 2 columns by default, up to 6 */
+@container (min-width: 1441px) {
+ .ui5-form-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ :host([columns-xl="1"]) .ui5-form-layout {
+ grid-template-columns: 1fr;
+ }
+ :host([columns-xl="2"]) .ui5-form-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ :host([columns-xl="3"]) .ui5-form-layout {
+ grid-template-columns: repeat(3, 1fr);
+ }
+ :host([columns-xl="4"]) .ui5-form-layout {
+ grid-template-columns: repeat(4, 1fr);
+ }
+ :host([columns-xl="5"]) .ui5-form-layout {
+ grid-template-columns: repeat(5, 1fr);
+ }
+ :host([columns-xl="6"]) .ui5-form-layout {
+ grid-template-columns: repeat(6, 1fr);
+ }
+
+ .ui5-form-column-spanXL-2 {
+ grid-column: span 2;
+ }
+ .ui5-form-column-spanXL-2 .ui5-form-group-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .ui5-form-column-spanXL-3 {
+ grid-column: span 3;
+ }
+ .ui5-form-column-spanXL-3 .ui5-form-group-layout {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ .ui5-form-column-spanXL-4 {
+ grid-column: span 4;
+ }
+ .ui5-form-column-spanXL-4 .ui5-form-group-layout {
+ grid-template-columns: repeat(4, 1fr);
+
+ }
+
+ .ui5-form-column-spanXL-5 {
+ grid-column: span 5;
+ }
+ .ui5-form-column-spanXL-5 .ui5-form-group-layout {
+ grid-template-columns: repeat(5, 1fr);
+
+ }
+
+ .ui5-form-column-spanXL-6 {
+ grid-column: span 6;
+ }
+ .ui5-form-column-spanXL-6 .ui5-form-group-layout {
+ grid-template-columns: repeat(6, 1fr);
+ }
+}
+
+.ui5-form-item-span-2 {
+ grid-column: span 2;
+}
+
+.ui5-form-item-span-3 {
+ grid-column: span 3;
+}
+
+.ui5-form-item-span-4 {
+ grid-column: span 4;
+}
+
+.ui5-form-item-span-5 {
+ grid-column: span 5;
+}
+.ui5-form-item-span-6 {
+ grid-column: span 6;
+}
diff --git a/packages/main/src/themes/base/Form-parameters.css b/packages/main/src/themes/base/Form-parameters.css
new file mode 100644
index 000000000000..958e9fb34292
--- /dev/null
+++ b/packages/main/src/themes/base/Form-parameters.css
@@ -0,0 +1,20 @@
+:root {
+ --ui5-form-item-layout: 1fr 2fr;
+ --ui5-form-item-layout-span1: 1fr 11fr;
+ --ui5-form-item-layout-span2: 2fr 10fr;
+ --ui5-form-item-layout-span3: 3fr 9fr;
+ --ui5-form-item-layout-span4: 4fr 8fr;
+ --ui5-form-item-layout-span5: 5fr 7fr;
+ --ui5-form-item-layout-span6: 6fr 6fr;
+ --ui5-form-item-layout-span7: 7fr 5fr;
+ --ui5-form-item-layout-span8: 8fr 4fr;
+ --ui5-form-item-layout-span9: 9fr 3fr;
+ --ui5-form-item-layout-span10: 10fr 2fr;
+ --ui5-form-item-layout-span11: 11fr 1fr;
+ --ui5-form-item-layout-span12: 1fr;
+ --ui5-form-item-label-justify: end;
+ --ui5-form-item-label-justify-span12: start;
+ --ui5-form-item-label-padding: 0.125rem 0;
+ --ui5-form-item-label-padding-end: 0.85rem;
+ --ui5-form-item-label-padding-span12: 0.625rem 0.25rem 0 0.25rem;
+}
\ No newline at end of file
diff --git a/packages/main/src/themes/base/sizes-parameters.css b/packages/main/src/themes/base/sizes-parameters.css
index d46f2f1d7a2c..350b85c58062 100644
--- a/packages/main/src/themes/base/sizes-parameters.css
+++ b/packages/main/src/themes/base/sizes-parameters.css
@@ -79,6 +79,11 @@
--_ui5_month_picker_item_height: 3rem;
--_ui5_list_buttons_left_space: 0.125rem;
+ /* Form */
+ --_ui5_form_item_min_height: 2.813rem;
+ --_ui5_form_item_padding: 0.65rem;
+ --_ui5-form-group-heading-height: 2.75rem;
+
/* Popup subclasses */
--_ui5_popup_default_header_height: 2.75rem;
@@ -241,6 +246,11 @@
--_ui5_dialog_content_min_height: 2.5rem;
--_ui5_dialog_footer_height: 2.5rem;
+ /* Form */
+ --_ui5_form_item_min_height: 2rem;
+ --_ui5_form_item_padding: 0.25rem;
+ --_ui5-form-group-heading-height: 2rem;
+
/* Input */
--_ui5_input_height: var(--sapElement_Compact_Height);
--_ui5_input_inner_padding: 0 0.5rem;
diff --git a/packages/main/src/themes/sap_horizon/parameters-bundle.css b/packages/main/src/themes/sap_horizon/parameters-bundle.css
index 8c58c954ed7b..b84a5584b55c 100644
--- a/packages/main/src/themes/sap_horizon/parameters-bundle.css
+++ b/packages/main/src/themes/sap_horizon/parameters-bundle.css
@@ -19,6 +19,7 @@
@import "../base/Dialog-parameters.css";
@import "./Dialog-parameters.css";
@import "./FileUploader-parameters.css";
+@import "../base/Form-parameters.css";
@import "../base/ListItemGroupHeader-parameters.css";
@import "./Icon-parameters.css";
@import "./Input-parameters.css";
diff --git a/packages/main/src/types/FormItemSpacing.ts b/packages/main/src/types/FormItemSpacing.ts
new file mode 100644
index 000000000000..cc6ffe9cc240
--- /dev/null
+++ b/packages/main/src/types/FormItemSpacing.ts
@@ -0,0 +1,21 @@
+/**
+ * Different Button designs.
+ *
+ * @public
+ * @since 2.0.0
+ */
+enum FormItemSpacing {
+ /**
+ * Normal spacing (smaller vertical space between form items).
+ * @public
+ */
+ Normal = "Normal",
+
+ /**
+ * Large spacing (larger vertical space between form items).
+ * @public
+ */
+ Large = "Large",
+}
+
+export default FormItemSpacing;
diff --git a/packages/main/test/pages/MessageStrip.html b/packages/main/test/pages/MessageStrip.html
index f5ad0161f038..073af57ec332 100644
--- a/packages/main/test/pages/MessageStrip.html
+++ b/packages/main/test/pages/MessageStrip.html
@@ -6,11 +6,6 @@
MessageStrip
-
@@ -71,4 +66,4 @@
});