diff --git a/src/interaction/siFamily.js b/src/interaction/siFamily.js
new file mode 100644
index 0000000000000000000000000000000000000000..da003bb94def359a83b82d877523987eeba05c97
--- /dev/null
+++ b/src/interaction/siFamily.js
@@ -0,0 +1,18 @@
+/**
+ * @returns {HTMLParagraphElement}
+ */
+App.UI.SlaveInteract.family = function() {
+	let element;
+	const p = document.createElement("p");
+	p.id= "family";
+
+	element = document.createElement("div");
+	element.id = "family-tree";
+	p.append(element);
+
+	element = document.createElement("span");
+	element.id = "family-tree-link";
+	p.append(element);
+
+	return p;
+};
diff --git a/src/interaction/slaveInteract.js b/src/interaction/slaveInteract.js
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9490e14a4039e2af2b512190d27bf4cbb03b35f3 100644
--- a/src/interaction/slaveInteract.js
+++ b/src/interaction/slaveInteract.js
@@ -0,0 +1,180 @@
+App.UI.SlaveInteract.mainPage = function(slave) {
+	const el = new DocumentFragment();
+	App.UI.tabBar.handlePreSelectedTab(V.tabChoice.SlaveInteract);
+
+	if (!assignmentVisible(slave)) {
+		switch (slave.assignment) {
+			case "work in the brothel":
+			case "be the Madam":
+				V.nextLink = "Brothel";
+				break;
+			case "be confined in the arcade":
+				V.nextLink = "Arcade";
+				break;
+			case "serve in the club":
+			case "be the DJ":
+				V.nextLink = "Club";
+				break;
+			case "work in the dairy":
+			case "be the Milkmaid":
+				V.nextLink = "Dairy";
+				break;
+			case "work as a farmhand":
+			case "be the Farmer":
+				V.nextLink = "Farmyard";
+				break;
+			case "rest in the spa":
+			case "be the Attendant":
+				V.nextLink = "Spa";
+				break;
+			case "work as a nanny":
+			case "be the Matron":
+				V.nextLink = "Nursery";
+				break;
+			case "learn in the schoolroom":
+			case "be the Schoolteacher":
+				V.nextLink = "Schoolroom";
+				break;
+			case "work as a servant":
+			case "be the Stewardess":
+				V.nextLink = "Servants' Quarters";
+				break;
+			case "serve in the master suite":
+			case "be your Concubine":
+				V.nextLink = "Master Suite";
+				break;
+			case "be confined in the cellblock":
+			case "be the Wardeness":
+				V.nextLink = "Cellblock";
+				break;
+			case "get treatment in the clinic":
+			case "be the Nurse":
+				V.nextLink = "Clinic";
+				break;
+			case "live with your Head Girl":
+				V.nextLink = "Head Girl Suite";
+				break;
+			case "be your agent":
+			case "live with your agent":
+				V.nextLink = "Neighbor Interact";
+		}
+	}
+
+	V.encyclopedia = either("Costs Summary", "Disease in the Free Cities", "Drugs and Their Effects", "From Rebellious to Devoted", "Gender", "Independent Slaves", "Modern Anal", "Nymphomania", "Slave Couture");
+	if (slave.dick > 0) {
+		V.encyclopedia = "Gender";
+	}
+	App.Utils.scheduleSidebarRefresh();
+
+	/**
+	 * @typedef {Object} siCategory
+	 * @property {string} title
+	 * @property {string} id
+	 * @property {Node} node
+	 * @property {Function} [onClick]
+	 */
+
+	 /** @type {Array<siCategory>} */
+	const buttons = [
+		{
+			title: "Description",
+			id: "description",
+			get node() { return App.UI.SlaveInteract.description(slave); }
+		},
+		{
+			title: "Modify",
+			id: "modify",
+			get node() { return App.UI.SlaveInteract.modify(slave); }
+		},
+		{
+			title: "Work",
+			id: "work",
+			get node() { return App.UI.SlaveInteract.work(slave); }
+		},
+		{
+			title: "Appearance",
+			id: "appearance",
+			get node() { return App.UI.SlaveInteract.wardrobe(slave); }
+		},
+		{
+			title: "Physical Regimen",
+			id: "physical-regimen",
+			get node() { return App.UI.SlaveInteract.physicalRegimen(slave); }
+		},
+		{
+			title: "Rules",
+			id: "rules",
+			get node() { return App.UI.SlaveInteract.rules(slave); }
+		},
+		{
+			title: "Financial",
+			id: "financial",
+			get node() { return App.UI.SlaveInteract.financial(slave); }
+		},
+		{
+			title: "Customize",
+			id: "customize",
+			get node() { return App.UI.SlaveInteract.custom(slave); }
+		},
+		{
+			 title: "Family",
+			 id: "family-tab",
+			 onClick: () => renderFamilyTree(V.slaves, slave.ID),
+			 get node() { return App.UI.SlaveInteract.family(); }
+		}
+	];
+
+	el.append(App.UI.SlaveInteract.navigation(slave));
+
+	el.append(displayWithTabs());
+
+	return el;
+
+	function displayWithTabs() {
+		const el = new DocumentFragment();
+
+		const tabBar = document.createElement("div");
+		tabBar.classList.add("tab-bar");
+		const tabContents = new DocumentFragment();
+
+		for (const item of buttons) {
+			tabBar.append(makeTabButton(item));
+			tabContents.append(makeTabContents(item));
+		}
+
+		el.append(tabBar);
+
+		App.Events.drawEventArt(el, slave);
+
+		el.append(tabContents);
+
+		return el;
+
+		function makeTabButton(item) {
+			const btn = document.createElement("button");
+			btn.className = "tab-links";
+			btn.id = `tab ${item.id}`;
+			btn.innerHTML = item.title;
+			btn.onclick = (event) => {
+				App.UI.tabBar.openTab(event, item.id);
+				if (item.hasOwnProperty("onClick")){
+					item.onClick();
+				}
+			};
+
+			return btn;
+		}
+
+		function makeTabContents(item){
+			const wrapperEl = document.createElement("div");
+			wrapperEl.id = item.id;
+			wrapperEl.classList.add("tab-content");
+
+			const classEl = document.createElement("div");
+			classEl.classList.add("content");
+			classEl.append(item.node);
+			wrapperEl.append(classEl);
+			return wrapperEl;
+		}
+	}
+};
diff --git a/src/uncategorized/slaveInteract.tw b/src/uncategorized/slaveInteract.tw
index ca883faec28b8b8eaf7fe66609a763dd38b31fa8..aea8b167fc824af6937dd5e2a7ee5102faea00a7 100644
--- a/src/uncategorized/slaveInteract.tw
+++ b/src/uncategorized/slaveInteract.tw
@@ -1,135 +1,5 @@
 :: Slave Interact [nobr jump-from-safe]
 
 <<set $nextButton = "Confirm changes", $nextLink = "Main">>
-<<set _SL = $slaves.length, _CL = $canines.length, _HL = $hooved.length, _FL = $felines.length>>
-<<run App.Utils.setLocalPronouns(getSlave($AS))>>
-<<run Enunciate(getSlave($AS))>>
-<style>
-.active {
-	background-color: grey;
-}
-</style>
 
-<<run App.UI.tabBar.handlePreSelectedTab($tabChoice.SlaveInteract)>>
-
-
-<<if !assignmentVisible(getSlave($AS))>>
-	<<switch getSlave($AS).assignment>>
-	<<case "work in the brothel" "be the Madam">>
-		<<set $nextLink = "Brothel">>
-	<<case "be confined in the arcade">>
-		<<set $nextLink = "Arcade">>
-	<<case "serve in the club" "be the DJ">>
-		<<set $nextLink = "Club">>
-	<<case "work in the dairy" "be the Milkmaid">>
-		<<set $nextLink = "Dairy">>
-	<<case "work as a farmhand" "be the Farmer">>
-		<<set $nextLink = "Farmyard">>
-	<<case "rest in the spa" "be the Attendant">>
-		<<set $nextLink = "Spa">>
-	<<case "work as a nanny" "be the Matron">>
-		<<set $nextLink = "Nursery">>
-	<<case "learn in the schoolroom" "be the Schoolteacher">>
-		<<set $nextLink = "Schoolroom">>
-	<<case "work as a servant" "be the Stewardess">>
-		<<set $nextLink = "Servants' Quarters">>
-	<<case "serve in the master suite" "be your Concubine">>
-		<<set $nextLink = "Master Suite">>
-	<<case "be confined in the cellblock" "be the Wardeness">>
-		<<set $nextLink = "Cellblock">>
-	<<case "get treatment in the clinic" "be the Nurse">>
-		<<set $nextLink = "Clinic">>
-	<<case "live with your Head Girl">>
-		<<set $nextLink = "Head Girl Suite">>
-	<<case "be your agent" "live with your agent">>
-		<<set $nextLink = "Neighbor Interact">>
-	<</switch>>
-<</if>>
-
-<<set $encyclopedia = either("Costs Summary", "Disease in the Free Cities", "Drugs and Their Effects", "From Rebellious to Devoted", "Gender", "Independent Slaves", "Modern Anal", "Nymphomania", "Slave Couture")>>
-<<if getSlave($AS).dick > 0>>
-	<<set $encyclopedia = "Gender">>
-<</if>>
-
-<<includeDOM App.UI.SlaveInteract.navigation(getSlave($AS))>>
-
-<div class="tab-bar">
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Description')" id="tab Description">Description</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Modify')" id="tab Modify">Modify</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Work')" id="tab Work">Work</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Appearance')" id="tab Appearance">Appearance</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'PhysicalRegimen')" id="tab PhysicalRegimen">Physical Regimen</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Rules')" id="tab Rules">Rules</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Financial')" id="tab Financial">Financial</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Customize')" id="tab Customize">Customize</button>
-	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'family-tab'), renderFamilyTree(V.slaves, V.AS)" id="tab family-tab">Family</button>
-</div>
-
-<div id="art-frame">
-	<<if $seeImages == 1>>
-		<<if $imageChoice == 1>>
-			<div class="imageRef lrgVector"><div class="mask">&nbsp;</div><<= SlaveArt(getSlave($AS), 3, 0)>></div>
-		<<else>>
-			<div class="imageRef lrgRender"><div class="mask">&nbsp;</div><<= SlaveArt(getSlave($AS), 3, 0)>></div>
-		<</if>>
-	<</if>>
-</div>
-
-<div id="Description" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.description(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="Modify" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.modify(getSlave(V.AS))>>
-	</div>
-</div>
-
-
-<div id="Work" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.work(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="Appearance" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.wardrobe(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="PhysicalRegimen" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.physicalRegimen(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="Rules" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.rules(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="Financial" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.financial(getSlave(V.AS))>>
-	</div>
-</div>
-
-<div id="Customize" class="tab-content">
-	<div class="content">
-		<<includeDOM App.UI.SlaveInteract.custom(getSlave(V.AS))>>
-		/*<<include "Add custom descriptors">>*/
-	</div>
-</div>
-
-<div id="family-tab" class="tab-content">
-	<div class="content">
-		<p id="family">
-			<div id="family-tree"></div>
-			<span id="family-tree-link"></span>
-		</p>
-	</div>
-</div>
+<<includeDOM App.UI.SlaveInteract.mainPage(getSlave(V.AS))>>