diff --git a/docs/features/software-templates/writing-custom-step-layouts.md b/docs/features/software-templates/writing-custom-step-layouts.md
new file mode 100644
index 0000000000..69d61b93dc
--- /dev/null
+++ b/docs/features/software-templates/writing-custom-step-layouts.md
@@ -0,0 +1,89 @@
+---
+id: writing-custom-step-layouts
+title: Writing custom step layouts
+description: How to override the default step form layout
+---
+
+Every form in each step rendered in the frontend uses the default form layout from [react-json-schema-form](https://react-jsonschema-form.readthedocs.io/). It is possible to override this behaviour by supplying a `ui:ObjectFieldTemplate` property for a particular step:
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ ui:ObjectFieldTemplate: TwoColumn
+```
+
+This is the same [field](https://react-jsonschema-form.readthedocs.io/en/latest/advanced-customization/custom-templates/#objectfieldtemplate) used by [react-json-schema-form](https://react-jsonschema-form.readthedocs.io/) but we need to add a couple of steps to ensure that the string value of `TwoColumn` above is resolved to a react component.
+
+## Registering a React component as a custom step layout
+
+The [createScaffolderLayout](https://backstage.io/docs/reference/plugin-scaffolder.createscaffolderlayout) function is used to mark a component as a custom step layout:
+
+```ts
+import React from 'react';
+import {
+ createScaffolderLayout,
+ LayoutTemplate,
+ scaffolderPlugin,
+} from '@backstage/plugin-scaffolder';
+import { Grid } from '@material-ui/core';
+
+const TwoColumn: LayoutTemplate = ({ properties, description, title }) => {
+ const mid = Math.ceil(properties.length / 2);
+
+ return (
+ <>
+
{title}
+ In two column layout!!
+
+ {properties.slice(0, mid).map(prop => (
+
+ {prop.content}
+
+ ))}
+ {properties.slice(mid).map(prop => (
+
+ {prop.content}
+
+ ))}
+
+ {description}
+ >
+ );
+};
+
+export const TwoColumnLayout = scaffolderPlugin.provide(
+ createScaffolderLayout({
+ name: 'TwoColumn',
+ component: TwoColumn,
+ }),
+);
+```
+
+After you have registered your component as a custom layout then you need to provide the `layouts` to the `ScaffolderPage`:
+
+```tsx
+import { MyCustomFieldExtension } from './scaffolder/MyCustomExtension';
+import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts';
+
+const routes = (
+
+ ...
+ }>
+
+
+
+
+ ...
+
+);
+```
+
+## Using the custom step layout
+
+Any component that has been passed to the `ScaffolderPage` as children of the `ScaffolderLayouts` component can be used as a `ui:ObjectFieldTemplate` in your template file:
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ ui:ObjectFieldTemplate: TwoColumn
+```
diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md
index a1cd50f271..826121bd02 100644
--- a/docs/features/software-templates/writing-templates.md
+++ b/docs/features/software-templates/writing-templates.md
@@ -258,6 +258,10 @@ use `ui:widget: password` or set some properties of `ui:backstage`:
show: false # won't print any info about 'hidden' property on Review Step
```
+### Custom step layouts
+
+If you find that the default layout of the form used in a particular step does not meet your needs then you can supply your own [custom step layout](./writing-custom-step-layouts.md).
+
### Remove sections or fields based on feature flags
Based on feature flags you can hide sections or even only fields of your
diff --git a/microsite/sidebars.json b/microsite/sidebars.json
index 41e54ccb29..f00b7b2ee1 100644
--- a/microsite/sidebars.json
+++ b/microsite/sidebars.json
@@ -97,6 +97,7 @@
"features/software-templates/builtin-actions",
"features/software-templates/writing-custom-actions",
"features/software-templates/writing-custom-field-extensions",
+ "features/software-templates/writing-custom-step-layouts",
"features/software-templates/migrating-from-v1beta2-to-v1beta3"
]
},
diff --git a/mkdocs.yml b/mkdocs.yml
index c0a8e3a182..8c86ae095d 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -64,6 +64,7 @@ nav:
- Writing Templates: 'features/software-templates/writing-templates.md'
- Builtin Actions: 'features/software-templates/builtin-actions.md'
- Writing Custom Actions: 'features/software-templates/writing-custom-actions.md'
+ - Writing Custom Step Layouts: 'features/software-templates/writing-custom-step-layouts.md'
- Writing Templates (Legacy): 'features/software-templates/legacy.md'
- Migrating from v1alpha1 to v1beta2 templates: 'features/software-templates/migrating-from-v1alpha1-to-v1beta2.md'
- Backstage Search:
diff --git a/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx b/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx
index 8dc6e5340a..b23d6e4073 100644
--- a/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx
+++ b/packages/app/src/components/scaffolder/customScaffolderLayouts.tsx
@@ -28,7 +28,6 @@ const TwoColumn: LayoutTemplate = ({ properties, description, title }) => {
return (
<>
{title}
- In two column layout!!
{left.map(prop => (