diff --git a/packages/css/src/components/field/README.md b/packages/css/src/components/field/README.md
new file mode 100644
index 0000000000..f6309aa776
--- /dev/null
+++ b/packages/css/src/components/field/README.md
@@ -0,0 +1,9 @@
+
+
+# Field
+
+Wraps around a single input and can indicate if that input has a validation error.
+
+## Guidelines
+
+Only use Field to wrap a single input. Use [Fieldset](/docs/components-forms-fieldset--docs) to wrap multiple inputs.
diff --git a/packages/css/src/components/field/field.scss b/packages/css/src/components/field/field.scss
new file mode 100644
index 0000000000..006502869f
--- /dev/null
+++ b/packages/css/src/components/field/field.scss
@@ -0,0 +1,13 @@
+/**
+ * @license EUPL-1.2+
+ * Copyright Gemeente Amsterdam
+ */
+
+.ams-field {
+ break-inside: avoid;
+}
+
+.ams-field__has-error {
+ border-inline-start: var(--ams-field-has-error-border-inline-start);
+ padding-inline-start: var(--ams-field-has-error-padding-inline-start);
+}
diff --git a/packages/css/src/components/index.scss b/packages/css/src/components/index.scss
index 063a49713e..b95b00fbdd 100644
--- a/packages/css/src/components/index.scss
+++ b/packages/css/src/components/index.scss
@@ -4,6 +4,7 @@
*/
/* Append here */
+@import "./field/field";
@import "./select/select";
@import "./time-input/time-input";
@import "./date-input/date-input";
diff --git a/packages/react/src/Field/Field.test.tsx b/packages/react/src/Field/Field.test.tsx
new file mode 100644
index 0000000000..baed851e41
--- /dev/null
+++ b/packages/react/src/Field/Field.test.tsx
@@ -0,0 +1,44 @@
+import { render } from '@testing-library/react'
+import { createRef } from 'react'
+import { Field } from './Field'
+import '@testing-library/jest-dom'
+
+describe('Field', () => {
+ it('renders', () => {
+ const { container } = render()
+ const component = container.querySelector(':only-child')
+
+ expect(component).toBeInTheDocument()
+ expect(component).toBeVisible()
+ })
+
+ it('renders a design system BEM class name', () => {
+ const { container } = render()
+ const component = container.querySelector(':only-child')
+
+ expect(component).toHaveClass('ams-field')
+ })
+
+ it('renders an additional class name', () => {
+ const { container } = render()
+ const component = container.querySelector(':only-child')
+
+ expect(component).toHaveClass('ams-field extra')
+ })
+
+ it('renders with the error class', () => {
+ const { container } = render()
+ const component = container.querySelector(':only-child')
+
+ expect(component).toHaveClass('ams-field__has-error')
+ })
+
+ it('supports ForwardRef in React', () => {
+ const ref = createRef()
+
+ const { container } = render()
+ const component = container.querySelector(':only-child')
+
+ expect(ref.current).toBe(component)
+ })
+})
diff --git a/packages/react/src/Field/Field.tsx b/packages/react/src/Field/Field.tsx
new file mode 100644
index 0000000000..21f78f4c61
--- /dev/null
+++ b/packages/react/src/Field/Field.tsx
@@ -0,0 +1,23 @@
+/**
+ * @license EUPL-1.2+
+ * Copyright Gemeente Amsterdam
+ */
+
+import clsx from 'clsx'
+import { forwardRef } from 'react'
+import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react'
+
+export type FieldProps = {
+ /** Whether the field has an input with a validation error */
+ hasError?: boolean
+} & PropsWithChildren>
+
+export const Field = forwardRef(
+ ({ children, className, hasError, ...restProps }: FieldProps, ref: ForwardedRef) => (
+
+ {children}
+
+ ),
+)
+
+Field.displayName = 'Field'
diff --git a/packages/react/src/Field/README.md b/packages/react/src/Field/README.md
new file mode 100644
index 0000000000..fb9b52624d
--- /dev/null
+++ b/packages/react/src/Field/README.md
@@ -0,0 +1,5 @@
+
+
+# React Field component
+
+[Field documentation](../../../css/src/components/field/README.md)
diff --git a/packages/react/src/Field/index.ts b/packages/react/src/Field/index.ts
new file mode 100644
index 0000000000..93ca84d382
--- /dev/null
+++ b/packages/react/src/Field/index.ts
@@ -0,0 +1,2 @@
+export { Field } from './Field'
+export type { FieldProps } from './Field'
diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts
index 70b5d5f6da..d6b0c721f6 100644
--- a/packages/react/src/index.ts
+++ b/packages/react/src/index.ts
@@ -4,6 +4,7 @@
*/
/* Append here */
+export * from './Field'
export * from './Select'
export * from './TimeInput'
export * from './DateInput'
diff --git a/proprietary/tokens/src/components/ams/field.tokens.json b/proprietary/tokens/src/components/ams/field.tokens.json
new file mode 100644
index 0000000000..5086be21de
--- /dev/null
+++ b/proprietary/tokens/src/components/ams/field.tokens.json
@@ -0,0 +1,14 @@
+{
+ "ams": {
+ "field": {
+ "has-error": {
+ "border-inline-start": {
+ "value": "3px solid {ams.color.primary-red}"
+ },
+ "padding-inline-start": {
+ "value": "{ams.space.inside.md}"
+ }
+ }
+ }
+ }
+}
diff --git a/storybook/src/components/Field/Field.docs.mdx b/storybook/src/components/Field/Field.docs.mdx
new file mode 100644
index 0000000000..b465ae15f5
--- /dev/null
+++ b/storybook/src/components/Field/Field.docs.mdx
@@ -0,0 +1,17 @@
+import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks";
+import * as FieldStories from "./Field.stories.tsx";
+import README from "../../../../packages/css/src/components/field/README.md?raw";
+
+
+
+{README}
+
+
+
+
+
+## With Error
+
+A Field can indicate if the contained input has a validation error.
+
+
diff --git a/storybook/src/components/Field/Field.stories.tsx b/storybook/src/components/Field/Field.stories.tsx
new file mode 100644
index 0000000000..50c37782cf
--- /dev/null
+++ b/storybook/src/components/Field/Field.stories.tsx
@@ -0,0 +1,44 @@
+/**
+ * @license EUPL-1.2+
+ * Copyright Gemeente Amsterdam
+ */
+
+import { TextInput } from '@amsterdam/design-system-react'
+import { Field, Label, Paragraph } from '@amsterdam/design-system-react/src'
+import { Meta, StoryObj } from '@storybook/react'
+
+const meta = {
+ title: 'Components/Forms/Field',
+ component: Field,
+ args: {
+ hasError: false,
+ },
+ render: (args) => (
+
+
+
+ Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u.
+
+
+
+ ),
+} satisfies Meta
+
+export default meta
+
+type Story = StoryObj
+
+export const Default: Story = {}
+
+export const WithError: Story = {
+ args: { hasError: true },
+ render: (args) => (
+
+
+
+ Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u.
+
+
+
+ ),
+}