diff --git a/frontend/components/PersonPage.tsx b/frontend/components/PersonPage.tsx
new file mode 100644
index 0000000..4cd2cfa
--- /dev/null
+++ b/frontend/components/PersonPage.tsx
@@ -0,0 +1,329 @@
+import Head from "next/head";
+import { Field, Name, Person, Pronoun, User, WordStatus } from "../lib/types";
+import ReactMarkdown from "react-markdown";
+import { userState } from "../lib/state";
+import { useRecoilValue } from "recoil";
+import FallbackImage from "./FallbackImage";
+import {
+  EmojiLaughing,
+  HandThumbsDown,
+  HandThumbsUp,
+  HeartFill,
+  People,
+} from "react-bootstrap-icons";
+import BlueLink from "./BlueLink";
+import React from "react";
+import Card from "./Card";
+
+export default function PersonPage({ person }: { person: Person }) {
+  return (
+    <>
+      
+        {`${personFullHandle(person)} - pronouns.cc`}
+      
+      
+      
+      
+        
+        
+        
+        
+        {"user" in person && 
}
+      
+      You are currently viewing your public user profile.
+      
+      Edit your profile
+    
+  ) : (
+    <>>
+  );
+}
+
+function MemberList({ user, className }: { user: User; className?: string }) {
+  const partialMembers = user.members;
+  return (
+    
+      
Members
+      
+        {partialMembers?.map((partialMember) => (
+          - 
+            
+              {partialMember.display_name ?? partialMember.name}
+            
+          +        ))}
+
+    
+      {/* display name */}
+      {display_name && 
{display_name}
}
+      {/* name */}
+      
+        {personFullHandle(person)}
+      
+      {/* bio */}
+      {bio && (
+        
+          {bio}
+        
+      )}
+      {/* links */}
+      {links?.length && (
+        
+          {links.map((link, index) => (
+            
+              {link}
+            
+          ))}
+        
+      )}
+    
+      {content.map((label, index) => (
+        
+      ))}
+    
+  ) : (
+    <>>
+  );
+}
+
+function LabelStatusIcon({ status }: { status: WordStatus }) {
+  return React.createElement(
+    {
+      [WordStatus.Favourite]: HeartFill,
+      [WordStatus.Okay]: HandThumbsUp,
+      [WordStatus.Jokingly]: EmojiLaughing,
+      [WordStatus.FriendsOnly]: People,
+      [WordStatus.Avoid]: HandThumbsDown,
+    }[status],
+    { className: "inline" }
+  );
+}
+
+function LabelsLine({ labels }: { labels: Name[] | Pronoun[] }) {
+  if (!labels?.length) return <>>;
+  const status = labels[0].status;
+  const text = labels
+    .map((label) =>
+      "name" in label
+        ? label.name
+        : label.display_text ?? label.pronouns.split("/").slice(0, 2).join("/")
+    )
+    .join(", ");
+  return (
+    
+       {text}
+    
+  );
+}
+
+function LabelLine({ label }: { label: Name | Pronoun }) {
+  return ;
+}
+
+function FieldCardGrid({ fields }: { fields: Field[] }) {
+  return (
+    
+      {fields?.map((field, index) => (
+        
+      ))}
+    
+  );
+}
+
+const fieldEntryStatus: { [key in string]: WordStatus } = {
+  favourite: WordStatus.Favourite,
+  okay: WordStatus.Okay,
+  jokingly: WordStatus.Jokingly,
+  friends_only: WordStatus.FriendsOnly,
+  avoid: WordStatus.Avoid,
+};
+
+function FieldCard({
+  field,
+  draggable,
+}: {
+  field: Field;
+  draggable?: boolean;
+}) {
+  return (
+    
+      {Object.entries(fieldEntryStatus).map(([statusName, status], i) => (
+         ({
+            name,
+            status,
+          }))}
+        />
+      ))}
+    
+  );
+}
diff --git a/frontend/pages/u/[user]/index.tsx b/frontend/pages/u/[user]/index.tsx
index bba091b..15f4901 100644
--- a/frontend/pages/u/[user]/index.tsx
+++ b/frontend/pages/u/[user]/index.tsx
@@ -1,31 +1,7 @@
 import { GetServerSideProps } from "next";
-import Head from "next/head";
+import PersonPage from "../../../components/PersonPage";
 import fetchAPI from "../../../lib/fetch";
-import {
-  Field,
-  Member,
-  Name,
-  PartialMember,
-  PartialUser,
-  Person,
-  Pronoun,
-  User,
-  WordStatus,
-} from "../../../lib/types";
-import ReactMarkdown from "react-markdown";
-import { userState } from "../../../lib/state";
-import { useRecoilValue } from "recoil";
-import FallbackImage from "../../../components/FallbackImage";
-import {
-  EmojiLaughing,
-  HandThumbsDown,
-  HandThumbsUp,
-  HeartFill,
-  People,
-} from "react-bootstrap-icons";
-import BlueLink from "../../../components/BlueLink";
-import React from "react";
-import Card from "../../../components/Card";
+import { PartialMember, User } from "../../../lib/types";
 
 interface Props {
   user: User;
@@ -33,9 +9,7 @@ interface Props {
 }
 
 export default function Index({ user, partialMembers }: Props) {
-  return (
-    
-  );
+  return ;
 }
 
 export const getServerSideProps: GetServerSideProps = async (context) => {
@@ -58,320 +32,3 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
     return { notFound: true };
   }
 };
-
-function PersonPage({ person }: { person: Person }) {
-  return (
-    <>
-      
-        {`${personFullHandle(person)} - pronouns.cc`}
-      
-      
-      
-      
-        
-        
-        
-        
-        { 'user' in person && (
-          
-        )}
-      
-      You are currently viewing your public user profile.
-      
-      Edit your profile
-    
-  ) : (
-    <>>
-  );
-}
-
-function MemberList({
-  user,
-  className,
-}: {
-  user: User;
-  className?: string;
-}) {
-  const partialMembers = user.members;
-  return (
-    
-      
Members
-      
-        {partialMembers?.map((partialMember) => (
-          - 
-            
-              {partialMember.display_name ?? partialMember.name}
-            
-          -        ))}
-
-    
-      {/* display name */}
-      {display_name && 
{display_name}
}
-      {/* name */}
-      
-        {personFullHandle(person)}
-      
-      {/* bio */}
-      {bio && (
-        
-          {bio}
-        
-      )}
-      {/* links */}
-      {links?.length && (
-        
-          {links.map((link, index) => (
-            
-              {link}
-            
-          ))}
-        
-      )}
-    
-      {content.map((label, index) => (
-        
-      ))}
-    
-  ) : (
-    <>>
-  );
-}
-
-function LabelStatusIcon({ status }: { status: WordStatus }) {
-  return React.createElement(
-    {
-      [WordStatus.Favourite]: HeartFill,
-      [WordStatus.Okay]: HandThumbsUp,
-      [WordStatus.Jokingly]: EmojiLaughing,
-      [WordStatus.FriendsOnly]: People,
-      [WordStatus.Avoid]: HandThumbsDown,
-    }[status],
-    { className: "inline" }
-  );
-}
-
-function LabelsLine({ labels }: { labels: Name[] | Pronoun[] }) {
-  if (!labels?.length) return <>>;
-  const status = labels[0].status;
-  const text = labels
-    .map((label) =>
-      "name" in label
-        ? label.name
-        : label.display_text ?? label.pronouns.split("/").slice(0, 2).join("/")
-    )
-    .join(", ");
-  return (
-    
-       {text}
-    
-  );
-}
-
-function LabelLine({ label }: { label: Name | Pronoun }) {
-  return ;
-}
-
-function FieldCardGrid({ fields }: { fields: Field[] }) {
-  return (
-    
-      {fields?.map((field, index) => (
-        
-      ))}
-    
-  );
-}
-
-const fieldEntryStatus: { [key in string]: WordStatus } = {
-  favourite: WordStatus.Favourite,
-  okay: WordStatus.Okay,
-  jokingly: WordStatus.Jokingly,
-  friends_only: WordStatus.FriendsOnly,
-  avoid: WordStatus.Avoid,
-};
-
-function FieldCard({
-  field,
-  draggable,
-}: {
-  field: Field;
-  draggable?: boolean;
-}) {
-  return (
-    
-      {Object.entries(fieldEntryStatus).map(([statusName, status], i) => (
-         ({
-            name,
-            status,
-          }))}
-        />
-      ))}
-    
-  );
-}