fix(ux): input error messages no longer overlap adjacent fields in forms (#21886)

## Context

`InputErrorHelper` used `position: absolute` which took the error
message out of normal document flow. In multi-field grid layouts (e.g.
the HTTP Request workflow node editor), this caused the error text to
render on top of the input below it instead of pushing it down.

## Solution

Removed `position: absolute` from `InputErrorHelper`. The error message
now participates in normal document flow and pushes subsequent content
downward, as expected in modern forms.

## Test plan

- [x] Open the HTTP Request node editor, fill in a field incorrectly —
error message appears below the field without overlapping the next input
- [x] Verify single-field forms still display error messages correctly

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21886?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Emmanuel Hernandez <emmanuel.hernandez@clickbalance.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Emmanuel Hernández Bazán
2026-06-24 11:07:33 -06:00
committed by GitHub
parent 6ee5413951
commit 33d2441a93
4 changed files with 35 additions and 6 deletions
@@ -5,7 +5,6 @@ import {
} from '@/advanced-text-editor/hooks/useAdvancedTextEditor';
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
import { InputHint } from '@/ui/input/components/InputHint';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { useFullScreenModal } from '@/ui/layout/fullscreen/hooks/useFullScreenModal';
@@ -243,7 +242,7 @@ export const FormAdvancedTextFieldInput = ({
</StyledAdvancedTextFieldInnerContainer>
</StyledAdvancedTextFieldFieldContainer>
{hint && <InputHint>{hint}</InputHint>}
{error && <InputErrorHelper>{error}</InputErrorHelper>}
{error && <InputHint danger>{error}</InputHint>}
</FormFieldInputContainer>
</StyledAdvancedTextFieldContainerWrapper>
@@ -4,7 +4,7 @@ import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form
import { TextVariableEditor } from '@/object-record/record-field/ui/form-types/components/TextVariableEditor';
import { useTextVariableEditor } from '@/object-record/record-field/ui/form-types/hooks/useTextVariableEditor';
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
import { InputHint } from '@/ui/input/components/InputHint';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { t } from '@lingui/core/macro';
import { useId } from 'react';
@@ -95,7 +95,7 @@ export const FormFilesFieldInput = ({
/>
)}
</FormFieldInputRowContainer>
<InputErrorHelper>{error}</InputErrorHelper>
{error && <InputHint danger>{error}</InputHint>}
</FormFieldInputContainer>
);
};
@@ -5,7 +5,7 @@ import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form
import { TextVariableEditor } from '@/object-record/record-field/ui/form-types/components/TextVariableEditor';
import { useTextVariableEditor } from '@/object-record/record-field/ui/form-types/hooks/useTextVariableEditor';
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
import { InputHint } from '@/ui/input/components/InputHint';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { useId } from 'react';
import { isDefined } from 'twenty-shared/utils';
@@ -90,7 +90,7 @@ export const FormRawJsonFieldInput = ({
/>
)}
</FormFieldInputRowContainer>
<InputErrorHelper>{error}</InputErrorHelper>
{error && <InputHint danger>{error}</InputHint>}
</FormFieldInputContainer>
);
};
@@ -17,6 +17,36 @@ export default meta;
type Story = StoryObj<typeof FormRawJsonFieldInput>;
export const WithError: Story = {
args: {
label: 'Body',
placeholder: 'Enter valid json',
error:
'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).',
onChange: fn(),
},
render: (args) => (
<div style={{ width: 240 }}>
<FormRawJsonFieldInput {...args} />
<FormRawJsonFieldInput
label="Headers"
placeholder="Enter valid json"
defaultValue={null}
onChange={fn()}
/>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const error = await canvas.findByText(
'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).',
);
expect(error).toBeVisible();
},
};
export const Default: Story = {
args: {
label: 'JSON field',