diff --git a/locales/en-US.yml b/locales/en-US.yml
index d736a7d881..116b8eabd0 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1226,6 +1226,8 @@ publishTimelinesDescription: "If enabled, the Local and Global timelines will be
   on {url} even when signed out."
 noAltTextWarning: "Some attached file(s) have no description. Did you forget to write?"
 showNoAltTextWarning: "Show a warning if you attempt to post files without a description"
+showAddFileDescriptionAtFirstPost: "Show add description page automatically when
+  first try to post a post attachment without a description"
 
 _emojiModPerm:
   unauthorized: "None"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index f67bf4a600..8f5d009acc 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -2058,5 +2058,6 @@ searchRangeDescription: "如果您要过滤时间段,请按以下格式输入
 messagingUnencryptedInfo: "Firefish 上的聊天没有经过端到端加密,请不要在聊天中分享您的敏感信息。"
 noAltTextWarning: 有些附件没有描述。您是否忘记写描述了?
 showNoAltTextWarning: 当您尝试发布没有描述的帖子附件时显示警告
+showAddFileDescriptionAtFirstPost: 当您首次尝试发布没有描述的帖子附件时自动弹出添加描述页面
 autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告
 incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?"
diff --git a/packages/client/src/components/MkPostForm.vue b/packages/client/src/components/MkPostForm.vue
index 6478838f4e..fee812317e 100644
--- a/packages/client/src/components/MkPostForm.vue
+++ b/packages/client/src/components/MkPostForm.vue
@@ -1013,32 +1013,43 @@ function deleteDraft() {
 	localStorage.setItem("drafts", JSON.stringify(draftData));
 }
 
-async function openFileDescriptionWindow(file: DriveFile) {
-	await os.popup(
-		XMediaCaption,
-		{
-			title: i18n.ts.describeFile,
-			input: {
-				placeholder: i18n.ts.inputNewDescription,
-				default: file.comment !== null ? file.comment : "",
+/**
+ * @returns whether the file is described
+ */
+ function openFileDescriptionWindow(file: entities.DriveFile) {
+	return new Promise<boolean>((resolve, reject) => {
+		os.popup(
+			XMediaCaption,
+			{
+				title: i18n.ts.describeFile,
+				input: {
+					placeholder: i18n.ts.inputNewDescription,
+					default: file.comment !== null ? file.comment : "",
+				},
+				image: file,
 			},
-			image: file,
-		},
-		{
-			done: (result) => {
-				if (!result || result.canceled) return;
-				const comment =
-					result.result.length === 0 ? null : result.result;
-				os.api("drive/files/update", {
-					fileId: file.id,
-					comment,
-				}).then(() => {
-					file.comment = comment;
-				});
+			{
+				done: (result) => {
+					if (!result || result.canceled) {
+						resolve(false);
+						return;
+					}
+					const comment =
+						result.result.length === 0 ? null : result.result;
+ 					os.api("drive/files/update", {
+						fileId: file.id,
+						comment,
+					}).then(() => {
+						resolve(true);
+						file.comment = comment;
+					}).catch((err: unknown) => {
+						reject(err);
+					});
+				},
 			},
-		},
-		"closed",
-	);
+			"closed",
+		);
+	})
 }
 
 async function post() {
@@ -1076,19 +1087,30 @@ async function post() {
 	}
 
 	if (
-		defaultStore.state.showNoAltTextWarning &&
+		defaultStore.state.showAddFileDescriptionAtFirstPost &&
 		files.value.some((f) => f.comment == null || f.comment.length === 0)
 	) {
 		if (isFirstPostAttempt) {
 			for (const file of files.value) {
 				if (file.comment == null || file.comment.length === 0) {
-					await openFileDescriptionWindow(file);
+					const described = await openFileDescriptionWindow(file);
+					if (!described) {
+						return;
+					}
 				}
 			}
 			isFirstPostAttempt = false;
-			return;
+			// Continue if all files have alt-text added.
+			if (files.value.some((f) => f.comment == null || f.comment.length === 0)) {
+				return;
+			}
 		}
+	}
 
+	if (
+		defaultStore.state.showNoAltTextWarning &&
+		files.value.some((f) => f.comment == null || f.comment.length === 0)
+	) {
 		// "canceled" means "post anyway"
 		const { canceled } = await os.confirm({
 			type: "warning",
@@ -1101,10 +1123,16 @@ async function post() {
 		if (!canceled) {
 			for (const file of files.value) {
 				if (file.comment == null || file.comment.length === 0) {
-					await openFileDescriptionWindow(file);
+					const described = await openFileDescriptionWindow(file);
+					if (!described) {
+						return;
+					}
 				}
 			}
-			return;
+			// Continue if all files have alt-text added.
+			if (files.value.some((f) => f.comment == null || f.comment.length === 0)) {
+				return;
+			}
 		}
 	}
 
diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue
index 15e1172169..bc21efc132 100644
--- a/packages/client/src/pages/settings/general.vue
+++ b/packages/client/src/pages/settings/general.vue
@@ -124,6 +124,9 @@
 			<FormSwitch v-model="showNoAltTextWarning" class="_formBlock">{{
 				i18n.ts.showNoAltTextWarning
 			}}</FormSwitch>
+			<FormSwitch v-model="showAddFileDescriptionAtFirstPost" class="_formBlock">{{
+				i18n.ts.showAddFileDescriptionAtFirstPost
+			}}</FormSwitch>
 			<FormSwitch v-model="autocorrectNoteLanguage" class="_formBlock">{{
 				i18n.ts.autocorrectNoteLanguage
 			}}</FormSwitch>
@@ -533,6 +536,9 @@ const pullToRefreshThreshold = computed(
 const showNoAltTextWarning = computed(
 	defaultStore.makeGetterSetter("showNoAltTextWarning"),
 );
+const showAddFileDescriptionAtFirstPost = computed(
+	defaultStore.makeGetterSetter("showAddFileDescriptionAtFirstPost"),
+);
 const autocorrectNoteLanguage = computed(
 	defaultStore.makeGetterSetter("autocorrectNoteLanguage"),
 );
diff --git a/packages/client/src/pages/settings/preferences-backups.vue b/packages/client/src/pages/settings/preferences-backups.vue
index 202de0a082..885fec70c1 100644
--- a/packages/client/src/pages/settings/preferences-backups.vue
+++ b/packages/client/src/pages/settings/preferences-backups.vue
@@ -125,6 +125,7 @@ const defaultStoreSaveKeys: (keyof (typeof defaultStore)["state"])[] = [
 	"enablePullToRefresh",
 	"pullToRefreshThreshold",
 	"showNoAltTextWarning",
+	"showAddFileDescriptionAtFirstPost",
 	"autocorrectNoteLanguage",
 ];
 const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
diff --git a/packages/client/src/store.ts b/packages/client/src/store.ts
index cf17917477..11abb2e30f 100644
--- a/packages/client/src/store.ts
+++ b/packages/client/src/store.ts
@@ -432,6 +432,10 @@ export const defaultStore = markRaw(
 			where: "account",
 			default: true,
 		},
+		showAddFileDescriptionAtFirstPost: {
+			where: "account",
+			default: false,
+		},
 		autocorrectNoteLanguage: {
 			where: "account",
 			default: true,