diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 938c815d9522b64d648df581cd39f0f7d6cb1e41..dccb7cad7894b84b4997d6250f4d6c380307358f 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -8,6 +8,7 @@
       "name": "greg",
       "version": "0.1.0",
       "dependencies": {
+        "@navikt/fnrvalidator": "^1.1.4",
         "@testing-library/jest-dom": "^5.14.1",
         "@testing-library/react": "^11.2.7",
         "@testing-library/user-event": "^12.8.3",
@@ -2805,6 +2806,11 @@
         "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
       }
     },
+    "node_modules/@navikt/fnrvalidator": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@navikt/fnrvalidator/-/fnrvalidator-1.1.4.tgz",
+      "integrity": "sha512-IroYFqa8PpzVxtIk6ifeEQBFzsI2QJX/FSIQyBtJvpp2D8Cb5Z9+hGNFppCILWR+QYbY8Dkk48la7K5fPGXeWQ=="
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -5155,15 +5161,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/bindings": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
-      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
-      "optional": true,
-      "dependencies": {
-        "file-uri-to-path": "1.0.0"
-      }
-    },
     "node_modules/bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -8791,12 +8788,6 @@
         "url": "https://opencollective.com/webpack"
       }
     },
-    "node_modules/file-uri-to-path": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
-      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
-      "optional": true
-    },
     "node_modules/filesize": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -9297,19 +9288,6 @@
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
-    "node_modules/fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
     "node_modules/function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -13664,12 +13642,6 @@
       "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
       "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
     },
-    "node_modules/nan": {
-      "version": "2.15.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
-      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
-      "optional": true
-    },
     "node_modules/nanoid": {
       "version": "3.1.25",
       "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
@@ -20426,24 +20398,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/watchpack-chokidar2/node_modules/fsevents": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-      "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "dependencies": {
-        "bindings": "^1.5.0",
-        "nan": "^2.12.1"
-      },
-      "engines": {
-        "node": ">= 4.0"
-      }
-    },
     "node_modules/watchpack-chokidar2/node_modules/glob-parent": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
@@ -20916,24 +20870,6 @@
         "node": ">=6"
       }
     },
-    "node_modules/webpack-dev-server/node_modules/fsevents": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-      "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "dependencies": {
-        "bindings": "^1.5.0",
-        "nan": "^2.12.1"
-      },
-      "engines": {
-        "node": ">= 4.0"
-      }
-    },
     "node_modules/webpack-dev-server/node_modules/glob-parent": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
@@ -24205,6 +24141,11 @@
         "chalk": "^4.0.0"
       }
     },
+    "@navikt/fnrvalidator": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@navikt/fnrvalidator/-/fnrvalidator-1.1.4.tgz",
+      "integrity": "sha512-IroYFqa8PpzVxtIk6ifeEQBFzsI2QJX/FSIQyBtJvpp2D8Cb5Z9+hGNFppCILWR+QYbY8Dkk48la7K5fPGXeWQ=="
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -26057,15 +25998,6 @@
       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
       "optional": true
     },
-    "bindings": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
-      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
-      "optional": true,
-      "requires": {
-        "file-uri-to-path": "1.0.0"
-      }
-    },
     "bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -28906,12 +28838,6 @@
         }
       }
     },
-    "file-uri-to-path": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
-      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
-      "optional": true
-    },
     "filesize": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -29300,12 +29226,6 @@
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
-    "fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-      "optional": true
-    },
     "function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -32658,12 +32578,6 @@
       "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
       "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
     },
-    "nan": {
-      "version": "2.15.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
-      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
-      "optional": true
-    },
     "nanoid": {
       "version": "3.1.25",
       "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
@@ -38010,16 +37924,6 @@
             }
           }
         },
-        "fsevents": {
-          "version": "1.2.13",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "optional": true,
-          "requires": {
-            "bindings": "^1.5.0",
-            "nan": "^2.12.1"
-          }
-        },
         "glob-parent": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
@@ -38637,16 +38541,6 @@
             "locate-path": "^3.0.0"
           }
         },
-        "fsevents": {
-          "version": "1.2.13",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "optional": true,
-          "requires": {
-            "bindings": "^1.5.0",
-            "nan": "^2.12.1"
-          }
-        },
         "glob-parent": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 8347e208a8cde6a655775345a315f2a3458eff85..307f95e4064e6b04df59f8675e9207bc40f0ea21 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -3,6 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@navikt/fnrvalidator": "^1.1.4",
     "@testing-library/jest-dom": "^5.14.1",
     "@testing-library/react": "^11.2.7",
     "@testing-library/user-event": "^12.8.3",
diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json
index 3e446301e09b80fec0560fad31d727e4f0e7d106..23b623dc27804e6390f5ce5422ae88d408e85172 100644
--- a/frontend/public/locales/en/common.json
+++ b/frontend/public/locales/en/common.json
@@ -6,6 +6,7 @@
   "language": {
     "change": "Change language to {{lang}}"
   },
+  "fnr": "National identity number",
   "header": {
     "applicationTitleShort": "GREG",
     "applicationTitleLong": "Guest Registration",
diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json
index 887180ac7c0f29a071985584d002416fa659c419..d916c4911609a188677a2bbf3dffcdf27761dbc4 100644
--- a/frontend/public/locales/nb/common.json
+++ b/frontend/public/locales/nb/common.json
@@ -6,6 +6,7 @@
   "language": {
     "change": "Bytt språk til {{lang}}"
   },
+  "fnr": "Fødselsnummer",
   "header":{
     "applicationTitleShort": "GREG",
     "applicationTitleLong": "Gjesteregistrering",
diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json
index 92c11d0febbfabda6240752d39f1573cbd218a8e..db11f21eacd26a8402d7d1244315094909efbe62 100644
--- a/frontend/public/locales/nn/common.json
+++ b/frontend/public/locales/nn/common.json
@@ -7,6 +7,7 @@
     "languageName": "Språk",
     "change": "Bytt språk til {{lang}}"
   },
+  "fnr": "National identity number",
   "header":{
     "applicationTitleShort": "GREG",
     "applicationTitleLong": "Gjesteregistrering",
diff --git a/frontend/src/components/form/fnr.tsx b/frontend/src/components/form/fnr.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..16e356125bdef88dfbae3e90d18164ef31e6b318
--- /dev/null
+++ b/frontend/src/components/form/fnr.tsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import validator from '@navikt/fnrvalidator'
+import { UseFormReturn } from 'react-hook-form'
+
+export function isValidIdnr(data: string) {
+  const validationResult = validator.idnr(data)
+  return validationResult.status === 'valid'
+}
+
+interface FnrProps extends Partial<Pick<UseFormReturn, 'register'>> {
+  name: string
+  errors?: any
+}
+
+function Fnr(props: FnrProps) {
+  const { register, name, errors } = props
+  if (register === undefined) {
+    return <></>
+  }
+
+  return (
+    <>
+      <input
+        type="text"
+        placeholder={name}
+        // eslint-disable-next-line react/jsx-props-no-spreading
+        {...register(name, {
+          required: 'Fnr is required',
+          validate: isValidIdnr,
+        })}
+        id="fnr"
+      />
+      {errors.fnr && errors.fnr.message}
+      {errors.fnr && errors.fnr.type === 'validate' && 'Invalid fnr'}
+    </>
+  )
+}
+
+Fnr.defaultProps = {
+  errors: {},
+}
+
+export default Fnr
diff --git a/frontend/src/components/form/form.tsx b/frontend/src/components/form/form.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..305eb2d302e1eb138480cff9399447c69d1c0e92
--- /dev/null
+++ b/frontend/src/components/form/form.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import { useForm } from 'react-hook-form'
+
+interface FormProps {
+  children: any
+  onSubmit: any
+}
+
+export default function Form(props: FormProps) {
+  const { children, onSubmit } = props
+  const methods = useForm()
+  const {
+    handleSubmit,
+    formState: { errors },
+  } = methods
+  return (
+    <form onSubmit={handleSubmit(onSubmit)}>
+      {React.Children.map(children, (child) =>
+        child.props.name
+          ? React.createElement(child.type, {
+              // eslint-disable-next-line react/jsx-props-no-spreading
+              ...{
+                // eslint-disable-next-line react/jsx-props-no-spreading
+                ...child.props,
+                register: methods.register,
+                errors,
+                key: child.props.name,
+              },
+            })
+          : child
+      )}
+    </form>
+  )
+}
diff --git a/frontend/src/components/form/index.tsx b/frontend/src/components/form/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1d3d7430ae22ba5e53a288393dc725ec272d84da
--- /dev/null
+++ b/frontend/src/components/form/index.tsx
@@ -0,0 +1,6 @@
+import Form from './form'
+import Input from './input'
+import Select from './select'
+import Fnr from './fnr'
+
+export { Fnr, Form, Input, Select }
diff --git a/frontend/src/components/form/input.tsx b/frontend/src/components/form/input.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..231a731c4b4be4fd8e98e684373dbba1bbca134f
--- /dev/null
+++ b/frontend/src/components/form/input.tsx
@@ -0,0 +1,25 @@
+import React from 'react'
+import { UseFormReturn } from 'react-hook-form'
+
+interface InputProps extends Partial<Pick<UseFormReturn, 'register'>> {
+  name: string
+  errors?: any
+  type?: 'text' | 'email' | 'number'
+}
+
+function Input(props: InputProps) {
+  // eslint-disable-next-line react/jsx-props-no-spreading
+  const { register, name, errors, type, ...rest } = props
+  if (register === undefined) {
+    return <></>
+  }
+  // eslint-disable-next-line react/jsx-props-no-spreading
+  return <input {...register(name)} {...rest} />
+}
+
+Input.defaultProps = {
+  type: 'text',
+  errors: {},
+}
+
+export default Input
diff --git a/frontend/src/components/form/select.tsx b/frontend/src/components/form/select.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e5eadbd4a9ce5ad91738f41946c79404eb99132a
--- /dev/null
+++ b/frontend/src/components/form/select.tsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import { UseFormReturn } from 'react-hook-form'
+
+interface SelectProps extends Partial<Pick<UseFormReturn, 'register'>> {
+  options: Array<string>
+  name: string
+  type?: 'text' | 'email' | 'number'
+}
+
+function Select(props: SelectProps) {
+  const { register, options, name, ...rest } = props
+  if (register === undefined) {
+    return <></>
+  }
+  return (
+    // eslint-disable-next-line react/jsx-props-no-spreading
+    <select {...register(name)} {...rest}>
+      {options.map((value) => (
+        <option key={value} value={value}>
+          {value}
+        </option>
+      ))}
+    </select>
+  )
+}
+
+Select.defaultProps = {
+  type: 'text',
+}
+
+export default Select
diff --git a/frontend/src/routes/frontpage/index.tsx b/frontend/src/routes/frontpage/index.tsx
index 29b2159c657bc51e985c5d121d72544940264c10..660d8d828220ff9678375c3dba128f579f73b4c4 100644
--- a/frontend/src/routes/frontpage/index.tsx
+++ b/frontend/src/routes/frontpage/index.tsx
@@ -2,10 +2,13 @@ import React, { useState } from 'react'
 
 import Page from 'components/page'
 import { appTimezone, appVersion, appTheme } from 'appConfig'
+import { Fnr, Form, Select, Input } from 'components/form'
+import { useTranslation } from 'react-i18next'
 
 export default function FrontPage() {
   const [apiHealth, setApiHealth] = useState('not yet')
   const [didContactApi, setDidContactApi] = useState(false)
+  const { t } = useTranslation(['common', 'footer'])
 
   if (!didContactApi) {
     setDidContactApi(true)
@@ -18,13 +21,22 @@ export default function FrontPage() {
           setApiHealth(result)
         }
       })
-        // eslint-disable-next-line @typescript-eslint/no-unused-vars
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
       .catch((error) => {
         setApiHealth('error')
       })
   }
+
   return (
     <Page header="Greg main page">
+      <Form onSubmit={() => {}}>
+        <Input name="firstName" />
+        <Input name="lastName" />
+        <Select name="gender" options={['female', 'male', 'other']} />
+        <Fnr name={t('common:fnr')} />
+        <button type="submit">Submit</button>
+      </Form>
+      <br />
       Version {appVersion}
       <br />
       Timezone {appTimezone}