diff --git a/app/src/lib/components/CommitCard.svelte b/app/src/lib/components/CommitCard.svelte
index 8a1fbd45a..715dba219 100644
--- a/app/src/lib/components/CommitCard.svelte
+++ b/app/src/lib/components/CommitCard.svelte
@@ -90,6 +90,7 @@
 	const hasCommitUrl = !commit.isLocal && commitUrl;
 
 	let commitMessageModal: Modal;
+	let commitMessageValid = false;
 	let description = '';
 
 	function openCommitMessageModal(e: Event) {
@@ -112,10 +113,16 @@
 </script>
 
 <Modal bind:this={commitMessageModal}>
-	<CommitMessageInput bind:commitMessage={description} />
+	<CommitMessageInput bind:commitMessage={description} bind:valid={commitMessageValid} />
 	<svelte:fragment slot="controls">
 		<Button style="ghost" kind="solid" on:click={() => commitMessageModal.close()}>Cancel</Button>
-		<Button style="pop" kind="solid" grow on:click={submitCommitMessageModal}>Submit</Button>
+		<Button
+			style="pop"
+			kind="solid"
+			grow
+			disabled={!commitMessageValid}
+			on:click={submitCommitMessageModal}>Submit</Button
+		>
 	</svelte:fragment>
 </Modal>
 
diff --git a/app/src/lib/components/CommitDialog.svelte b/app/src/lib/components/CommitDialog.svelte
index 50d31ab8c..4e7176c3b 100644
--- a/app/src/lib/components/CommitDialog.svelte
+++ b/app/src/lib/components/CommitDialog.svelte
@@ -22,6 +22,8 @@
 
 	let isCommitting = false;
 
+	let commitMessageValid = false;
+
 	async function commit() {
 		const message = $commitMessage;
 		isCommitting = true;
@@ -42,7 +44,11 @@
 <div class="commit-box" class:commit-box__expanded={$expanded}>
 	{#if $expanded}
 		<div class="commit-box__expander" transition:slide={{ duration: 150, easing: quintOut }}>
-			<CommitMessageInput bind:commitMessage={$commitMessage} {commit} />
+			<CommitMessageInput
+				bind:commitMessage={$commitMessage}
+				bind:valid={commitMessageValid}
+				{commit}
+			/>
 		</div>
 	{/if}
 	<div class="actions">
@@ -63,7 +69,7 @@
 			kind="solid"
 			grow
 			loading={isCommitting}
-			disabled={(isCommitting || !$commitMessage || $selectedOwnership.isEmpty()) && $expanded}
+			disabled={(isCommitting || !commitMessageValid || $selectedOwnership.isEmpty()) && $expanded}
 			id="commit-to-branch"
 			on:click={() => {
 				if ($expanded) {
diff --git a/app/src/lib/components/CommitMessageInput.svelte b/app/src/lib/components/CommitMessageInput.svelte
index 3b8e7db8c..1d3335882 100644
--- a/app/src/lib/components/CommitMessageInput.svelte
+++ b/app/src/lib/components/CommitMessageInput.svelte
@@ -25,6 +25,7 @@
 	import { fly } from 'svelte/transition';
 
 	export let commitMessage: string;
+	export let valid: boolean = false;
 	export let commit: (() => void) | undefined = undefined;
 
 	const user = getContextStore(User);
@@ -51,6 +52,7 @@
 
 	$: ({ title, description } = splitMessage(commitMessage));
 	$: if (commitMessage) updateHeights();
+	$: valid = !!title;
 
 	function concatMessage(title: string, description: string) {
 		return `${title}\n\n${description}`;