diff --git a/src/client/components/form/suspense.vue b/src/client/components/form/suspense.vue
index 4b47cb959b..e22b09ada4 100644
--- a/src/client/components/form/suspense.vue
+++ b/src/client/components/form/suspense.vue
@@ -1,16 +1,20 @@
 <template>
-<div class="_formItem" v-if="pending">
-	<div class="_formPanel">
-		pending
+<transition name="fade" mode="out-in">
+	<div class="_formItem" v-if="pending">
+		<div class="_formPanel">
+			<MkLoading/>
+		</div>
 	</div>
-</div>
-<slot v-else-if="resolved" :result="result"></slot>
-<div class="_formItem" v-else>
-	<div class="_formPanel">
-		error!
-		<button @click="retry">retry</button>
+	<div v-else-if="resolved">
+		<slot :result="result"></slot>
 	</div>
-</div>
+	<div class="_formItem" v-else>
+		<div class="_formPanel">
+			error!
+			<button @click="retry">retry</button>
+		</div>
+	</div>
+</transition>
 </template>
 
 <script lang="ts">
@@ -72,5 +76,13 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
+.fade-enter-active,
+.fade-leave-active {
+	transition: opacity 0.125s ease;
+}
 
+.fade-enter-from,
+.fade-leave-to {
+	opacity: 0;
+}
 </style>
diff --git a/src/client/components/global/loading.vue b/src/client/components/global/loading.vue
index 5d0c10c086..17d71b5c7b 100644
--- a/src/client/components/global/loading.vue
+++ b/src/client/components/global/loading.vue
@@ -1,5 +1,5 @@
 <template>
-<div class="yxspomdl" :class="{ inline }">
+<div class="yxspomdl" :class="{ inline, colored }">
 	<div class="ring"></div>
 </div>
 </template>
@@ -14,6 +14,11 @@ export default defineComponent({
 			type: Boolean,
 			required: false,
 			default: false
+		},
+		colored: {
+			type: Boolean,
+			required: false,
+			default: true
 		}
 	}
 });
@@ -32,6 +37,11 @@ export default defineComponent({
 .yxspomdl {
 	padding: 32px;
 	text-align: center;
+	cursor: wait;
+
+	&.colored {
+		color: var(--accent);
+	}
 
 	&.inline {
 		display: inline;
@@ -41,24 +51,43 @@ export default defineComponent({
 			width: 32px;
 			height: 32px;
 		}
+
+		> .ring {
+			&:before,
+			&:after {
+				width: 32px;
+				height: 32px;
+			}
+		}
 	}
 
 	> .ring {
+		position: relative;
 		display: inline-block;
-		opacity: 0.7;
 		vertical-align: middle;
-	}
 
-	> .ring:after {
-		content: " ";
-		display: block;
-		box-sizing: border-box;
-		width: 48px;
-		height: 48px;
-		border-radius: 50%;
-		border: solid 4px;
-		border-color: currentColor transparent transparent transparent;
-		animation: ring 0.5s linear infinite;
+		&:before,
+		&:after {
+			content: " ";
+			display: block;
+			box-sizing: border-box;
+			width: 48px;
+			height: 48px;
+			border-radius: 50%;
+			border: solid 4px;
+		}
+
+		&:before {
+			border-color: currentColor;
+			opacity: 0.3;
+		}
+
+		&:after {
+			position: absolute;
+			top: 0;
+			border-color: currentColor transparent transparent transparent;
+			animation: ring 0.5s linear infinite;
+		}
 	}
 }
 </style>
diff --git a/src/client/pages/user-ap-info.vue b/src/client/pages/user-ap-info.vue
index d86437830d..3f2920402f 100644
--- a/src/client/pages/user-ap-info.vue
+++ b/src/client/pages/user-ap-info.vue
@@ -1,8 +1,8 @@
 <template>
 <FormBase>
-	<FormGroup>
-		<template #label>ActivityPub</template>
-		<FormSuspense :p="apPromiseFactory" v-slot="{ result: ap }">
+	<FormSuspense :p="apPromiseFactory" v-slot="{ result: ap }">
+		<FormGroup>
+			<template #label>ActivityPub</template>
 			<FormKeyValueView>
 				<template #key>Type</template>
 				<template #value><span class="_monospace">{{ ap.type }}</span></template>
@@ -48,8 +48,8 @@
 				<template #key>{{ $ts.instanceInfo }}</template>
 				<template #value>(Local user)</template>
 			</FormKeyValueView>
-		</FormSuspense>
-	</FormGroup>
+		</FormGroup>
+	</FormSuspense>
 </FormBase>
 </template>