From 33d2441a936f8f688f22bc59d34f465e4eec7df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Hern=C3=A1ndez=20Baz=C3=A1n?= <126545166+emmanuelhb56@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:07:33 -0600 Subject: [PATCH] fix(ux): input error messages no longer overlap adjacent fields in forms (#21886) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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) Review in cubic --------- Co-authored-by: Emmanuel Hernandez Co-authored-by: Charles Bochet --- .../components/FormAdvancedTextFieldInput.tsx | 3 +- .../components/FormFilesFieldInput.tsx | 4 +-- .../components/FormRawJsonFieldInput.tsx | 4 +-- .../FormRawJsonFieldInput.stories.tsx | 30 +++++++++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput.tsx index ac486438bc..e2afaf6f18 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormAdvancedTextFieldInput.tsx @@ -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 = ({ {hint && {hint}} - {error && {error}} + {error && {error}} diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormFilesFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormFilesFieldInput.tsx index c3ca9dd110..9910380d59 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormFilesFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormFilesFieldInput.tsx @@ -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 = ({ /> )} - {error} + {error && {error}} ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormRawJsonFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormRawJsonFieldInput.tsx index 41f46b95d3..68ba71af11 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormRawJsonFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormRawJsonFieldInput.tsx @@ -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 = ({ /> )} - {error} + {error && {error}} ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormRawJsonFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormRawJsonFieldInput.stories.tsx index a3c46f337a..4ee0de171a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormRawJsonFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/__stories__/FormRawJsonFieldInput.stories.tsx @@ -17,6 +17,36 @@ export default meta; type Story = StoryObj; +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) => ( +
+ + +
+ ), + 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',