diff --git a/src/components/NewUI/App.tsx b/src/components/NewUI/App.tsx
index 136a741..cf857c1 100644
--- a/src/components/NewUI/App.tsx
+++ b/src/components/NewUI/App.tsx
@@ -1,3 +1,4 @@
+import EventCreator from './EventCreator';
 import Group from './Group';
 import UIPrimaryTitle from './UIPrimaryTitle';
 
@@ -15,6 +16,7 @@ export default function App() {
 			}}
 		>
 			<UIPrimaryTitle>WheelShare</UIPrimaryTitle>
+			<EventCreator />
 			<Group
 				events={[
 					{
diff --git a/src/components/NewUI/Event.tsx b/src/components/NewUI/Event.tsx
index 47c6550..e98a50f 100644
--- a/src/components/NewUI/Event.tsx
+++ b/src/components/NewUI/Event.tsx
@@ -1,5 +1,7 @@
 import { useEffect, useState } from 'react';
+import UIButton from './UIButton';
 import UIPlacesAutocomplete from './UIPlacesAutocomplete';
+import UISecondaryBox from './UISecondaryBox';
 import UISecondaryHeader from './UISecondaryHeader';
 import UITimeInput from './UITimeInput';
 
@@ -25,16 +27,7 @@ export default function Event({ title, group, location, time }: IEvent) {
 	}, [rideTherePickupPlaceID, rideBackDropoffPlaceID]);
 
 	return (
-		<div
-			style={{
-				display: 'flex',
-				flexDirection: 'column',
-				backgroundColor: '#f9f9f9',
-				borderRadius: '0.5rem',
-				padding: '1rem',
-				marginBottom: '1em',
-			}}
-		>
+		<UISecondaryBox>
 			<UISecondaryHeader>{title}</UISecondaryHeader>
 			<span
 				style={{
@@ -76,44 +69,32 @@ export default function Event({ title, group, location, time }: IEvent) {
 					marginTop: '1rem',
 				}}
 			>
-				<div
+				<UIButton
 					style={{
 						backgroundColor: needRideThere ? green : lightgrey,
 						color: needRideThere ? 'white' : 'black',
 						transition: 'color 0.2s, background-color 0.2s',
-						padding: '1rem',
-						borderRadius: '0.5em',
-						textTransform: 'uppercase',
-						fontWeight: 500,
 						marginRight: '0.5em',
-						cursor: 'pointer',
-						userSelect: 'none',
 					}}
 					onClick={() => {
 						setNeedRideThere((needRideThere) => !needRideThere);
 					}}
 				>
 					I need a ride there
-				</div>
-				<div
+				</UIButton>
+				<UIButton
 					style={{
 						backgroundColor: needRideBack ? green : lightgrey,
 						color: needRideBack ? 'white' : 'black',
 						transition: 'color 0.2s, background-color 0.2s',
-						padding: '1rem',
-						borderRadius: '0.5em',
-						textTransform: 'uppercase',
-						fontWeight: 500,
 						marginLeft: '0.5em',
-						cursor: 'pointer',
-						userSelect: 'none',
 					}}
 					onClick={() => {
 						setNeedRideBack((needRideBack) => !needRideBack);
 					}}
 				>
 					I need a ride back
-				</div>
+				</UIButton>
 			</div>
 			{needRideThere && (
 				<>
@@ -161,25 +142,18 @@ export default function Event({ title, group, location, time }: IEvent) {
 			)}
 			{(needRideThere || needRideBack) &&
 				(rideTherePickupPlaceID || rideBackDropoffPlaceID) && (
-					<div
+					<UIButton
 						style={{
 							backgroundColor: confirmed ? green : lightgrey,
 							color: confirmed ? 'white' : 'black',
-							padding: '1rem',
-							borderRadius: '0.5em',
-							textTransform: 'uppercase',
-							fontWeight: 500,
-							marginTop: '0.5em',
-							cursor: 'pointer',
-							userSelect: 'none',
 						}}
 						onClick={() => {
 							setConfirmed((confirmed) => !confirmed);
 						}}
 					>
 						{confirmed ? 'Confirmed' : 'Confirm'}
-					</div>
+					</UIButton>
 				)}
-		</div>
+		</UISecondaryBox>
 	);
 }
diff --git a/src/components/NewUI/EventCreator.tsx b/src/components/NewUI/EventCreator.tsx
new file mode 100644
index 0000000..96c2cb0
--- /dev/null
+++ b/src/components/NewUI/EventCreator.tsx
@@ -0,0 +1,53 @@
+import { useCallback, useState } from 'react';
+import UIButton from './UIButton';
+import UIDatetimeInput from './UIDatetimeInput';
+import UIPlacesAutocomplete from './UIPlacesAutocomplete';
+import UISecondaryBox from './UISecondaryBox';
+import UITextInput from './UITextInput';
+
+export default function EventCreator() {
+	const [name, setName] = useState('');
+	const [startTime, setStartTime] = useState<Date | null>(null);
+	const [endTime, setEndTime] = useState<Date | null>(null);
+	const [placeId, setPlaceId] = useState<string | null>(null);
+	const [groupId, setGroupId] = useState('');
+
+	const createEvent = useCallback(() => {
+		fetch('http://localhost:5000/api/events', {
+			method: 'post',
+			body: JSON.stringify({
+				name,
+				startTime,
+				endTime,
+				groupId,
+			}),
+			headers: {
+				'Content-Type': 'application/json',
+			},
+		});
+	}, [name, startTime, endTime, groupId]);
+
+	return (
+		<UISecondaryBox style={{ width: '100%', boxSizing: 'border-box' }}>
+			Name
+			<UITextInput value={name} onChangeText={setName} />
+			<br />
+			Group
+			<UITextInput value={groupId} onChangeText={setGroupId} />
+			<br />
+			Start time
+			<UIDatetimeInput onChangedDate={setStartTime} />
+			<br />
+			End time
+			<UIDatetimeInput onChangedDate={setEndTime} />
+			<br />
+			Location
+			<UIPlacesAutocomplete
+				onSelected={(address, placeId) => {
+					setPlaceId(placeId);
+				}}
+			/>
+			<UIButton onClick={createEvent}>Create Event</UIButton>
+		</UISecondaryBox>
+	);
+}
diff --git a/src/components/NewUI/Group.tsx b/src/components/NewUI/Group.tsx
index 073ac3c..a508b19 100644
--- a/src/components/NewUI/Group.tsx
+++ b/src/components/NewUI/Group.tsx
@@ -7,9 +7,9 @@ export type IGroup = {
 
 export default function Group({ events, name }: IGroup) {
 	return (
-		<div style={{ textAlign: 'center' }}>
+		<div style={{ textAlign: 'center', width: '100%' }}>
 			<h1>{name}</h1>
-			<div style={{ display: 'flex', flexDirection: 'column' }}>
+			<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
 				{events.map((event) => (
 					<Event {...event} key={event.title} />
 				))}
diff --git a/src/components/NewUI/UIButton.tsx b/src/components/NewUI/UIButton.tsx
new file mode 100644
index 0000000..483813f
--- /dev/null
+++ b/src/components/NewUI/UIButton.tsx
@@ -0,0 +1,33 @@
+import { useMemo, CSSProperties, MouseEventHandler, ReactNode } from 'react';
+
+const baseStyle: CSSProperties = {
+	padding: '1rem',
+	borderRadius: '0.5em',
+	textTransform: 'uppercase',
+	fontWeight: 500,
+	marginTop: '0.5em',
+	cursor: 'pointer',
+	userSelect: 'none',
+};
+
+export default function UIButton({
+	style,
+	children,
+	onClick,
+}: {
+	style?: CSSProperties;
+	children: ReactNode;
+	onClick: MouseEventHandler<HTMLDivElement>;
+}) {
+	const computedStyle = useMemo(() => {
+		if (!style) {
+			return baseStyle;
+		}
+		return { ...baseStyle, ...style };
+	}, [style]);
+	return (
+		<div style={computedStyle} onClick={onClick}>
+			{children}
+		</div>
+	);
+}
diff --git a/src/components/NewUI/UIDatetimeInput.tsx b/src/components/NewUI/UIDatetimeInput.tsx
new file mode 100644
index 0000000..156a6d3
--- /dev/null
+++ b/src/components/NewUI/UIDatetimeInput.tsx
@@ -0,0 +1,22 @@
+const baseStyle = {
+	marginTop: '0.5em',
+	padding: '0.5em',
+	fontFamily: 'Inter',
+	fontSize: '1.25rem',
+	borderRadius: '0.5em',
+	border: '0px',
+};
+
+export default function UIDatetimeInput({
+	onChangedDate,
+}: {
+	onChangedDate: (date: Date | null) => void;
+}) {
+	return (
+		<input
+			style={baseStyle}
+			type="datetime-local"
+			onChange={(e) => onChangedDate(e.target.valueAsDate)}
+		/>
+	);
+}
diff --git a/src/components/NewUI/UISecondaryBox.tsx b/src/components/NewUI/UISecondaryBox.tsx
new file mode 100644
index 0000000..d38c94b
--- /dev/null
+++ b/src/components/NewUI/UISecondaryBox.tsx
@@ -0,0 +1,26 @@
+import { CSSProperties, ReactNode, useMemo } from 'react';
+
+const baseStyle: CSSProperties = {
+	display: 'flex',
+	flexDirection: 'column',
+	backgroundColor: '#f9f9f9',
+	borderRadius: '0.5rem',
+	padding: '1rem',
+	marginBottom: '1em',
+};
+
+export default function UISecondaryBox({
+	children,
+	style,
+}: {
+	children: ReactNode;
+	style?: CSSProperties;
+}) {
+	const computedStyle = useMemo(() => {
+		if (!style) {
+			return baseStyle;
+		}
+		return { ...baseStyle, ...style };
+	}, [style]);
+	return <div style={computedStyle}>{children}</div>;
+}
diff --git a/src/components/NewUI/UITextInput.tsx b/src/components/NewUI/UITextInput.tsx
new file mode 100644
index 0000000..50339f6
--- /dev/null
+++ b/src/components/NewUI/UITextInput.tsx
@@ -0,0 +1,24 @@
+const baseStyle = {
+	marginTop: '0.5em',
+	padding: '0.5em',
+	fontFamily: 'Inter',
+	fontSize: '1.25rem',
+	borderRadius: '0.5em',
+	border: '0px',
+};
+
+export default function UITextInput({
+	value,
+	onChangeText,
+}: {
+	value: string;
+	onChangeText: (text: string) => void;
+}) {
+	return (
+		<input
+			style={baseStyle}
+			value={value}
+			onChange={(e) => onChangeText(e.target.value)}
+		/>
+	);
+}