diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue
index 7ef727d571..d46174acc1 100644
--- a/packages/client/src/components/form/range.vue
+++ b/packages/client/src/components/form/range.vue
@@ -16,162 +16,126 @@
 </div>
 </template>
 
-<script lang="ts">
-import { computed, defineAsyncComponent, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
+<script lang="ts" setup>
+import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch } from 'vue';
 import * as os from '@/os';
 
-export default defineComponent({
-	props: {
-		modelValue: {
-			type: Number,
-			required: false,
-			default: 0,
-		},
-		disabled: {
-			type: Boolean,
-			required: false,
-			default: false,
-		},
-		min: {
-			type: Number,
-			required: false,
-			default: 0,
-		},
-		max: {
-			type: Number,
-			required: false,
-			default: 100,
-		},
-		step: {
-			type: Number,
-			required: false,
-			default: 1,
-		},
-		autofocus: {
-			type: Boolean,
-			required: false,
-		},
-		textConverter: {
-			type: Function,
-			required: false,
-			default: (v) => v.toString(),
-		},
-	},
-
-	setup(props, context) {
-		const containerEl = ref<HTMLElement>();
-		const thumbEl = ref<HTMLElement>();
-
-		const rawValue = ref((props.modelValue - props.min) / (props.max - props.min));
-		const steppedRawValue = computed(() => {
-			if (props.step) {
-				const step = props.step / (props.max - props.min);
-				return (step * Math.round(rawValue.value / step));
-			} else {
-				return rawValue.value;
-			}
-		});
-		const finalValue = computed(() => {
-			if (Number.isInteger(props.step)) {
-				return Math.round((steppedRawValue.value * (props.max - props.min)) + props.min);
-			} else {
-				return (steppedRawValue.value * (props.max - props.min)) + props.min;
-			}
-		});
-
-		const thumbWidth = computed(() => {
-			if (thumbEl.value == null) return 0;
-			return thumbEl.value!.offsetWidth;
-		});
-		const thumbPosition = ref(0);
-		const calcThumbPosition = () => {
-			if (containerEl.value == null) {
-				thumbPosition.value = 0;
-			} else {
-				thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value;
-			}
-		};
-		watch([steppedRawValue, containerEl], calcThumbPosition);
-
-		let ro: ResizeObserver | undefined;
-
-		onMounted(() => {
-			ro = new ResizeObserver((entries, observer) => {
-				calcThumbPosition();
-			});
-			ro.observe(containerEl.value);
-		});
-		
-		onUnmounted(() => {
-			if (ro) ro.disconnect();
-		});
-
-		const steps = computed(() => {
-			if (props.step) {
-				return (props.max - props.min) / props.step;
-			} else {
-				return 0;
-			}
-		});
-
-		const onMousedown = (ev: MouseEvent | TouchEvent) => {
-			ev.preventDefault();
-
-			const tooltipShowing = ref(true);
-			os.popup(defineAsyncComponent(() => import('@/components/ui/tooltip.vue')), {
-				showing: tooltipShowing,
-				text: computed(() => {
-					return props.textConverter(finalValue.value);
-				}),
-				targetElement: thumbEl,
-			}, {}, 'closed');
-
-			const style = document.createElement('style');
-			style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
-			document.head.appendChild(style);
-
-			const onDrag = (ev: MouseEvent | TouchEvent) => {
-				ev.preventDefault();
-				const containerRect = containerEl.value!.getBoundingClientRect();
-				const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX;
-				const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2));
-				rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value)));
-			};
-
-			let beforeValue = finalValue.value;
-
-			const onMouseup = () => {
-				document.head.removeChild(style);
-				tooltipShowing.value = false;
-				window.removeEventListener('mousemove', onDrag);
-				window.removeEventListener('touchmove', onDrag);
-				window.removeEventListener('mouseup', onMouseup);
-				window.removeEventListener('touchend', onMouseup);
-
-				// 値が変わってたら通知
-				if (beforeValue !== finalValue.value) {
-					context.emit('update:modelValue', finalValue.value);
-				}
-			};
-
-			window.addEventListener('mousemove', onDrag);
-			window.addEventListener('touchmove', onDrag);
-			window.addEventListener('mouseup', onMouseup, { once: true });
-			window.addEventListener('touchend', onMouseup, { once: true });
-		};
-
-		return {
-			rawValue,
-			finalValue,
-			steppedRawValue,
-			onMousedown,
-			containerEl,
-			thumbEl,
-			thumbPosition,
-			steps,
-		};
-	},
+const props = withDefaults(defineProps<{
+	modelValue: number;
+	disabled?: boolean;
+	min: number;
+	max: number;
+	step?: number;
+	textConverter?: (value: number) => string,
+}>(), {
+	step: 1,
+	textConverter: (v) => v.toString(),
 });
+
+const emit = defineEmits<{
+	(ev: 'update:modelValue', value: number): void;
+}>();
+
+const containerEl = ref<HTMLElement>();
+const thumbEl = ref<HTMLElement>();
+
+const rawValue = ref((props.modelValue - props.min) / (props.max - props.min));
+const steppedRawValue = computed(() => {
+	if (props.step) {
+		const step = props.step / (props.max - props.min);
+		return (step * Math.round(rawValue.value / step));
+	} else {
+		return rawValue.value;
+	}
+});
+const finalValue = computed(() => {
+	if (Number.isInteger(props.step)) {
+		return Math.round((steppedRawValue.value * (props.max - props.min)) + props.min);
+	} else {
+		return (steppedRawValue.value * (props.max - props.min)) + props.min;
+	}
+});
+
+const thumbWidth = computed(() => {
+	if (thumbEl.value == null) return 0;
+	return thumbEl.value!.offsetWidth;
+});
+const thumbPosition = ref(0);
+const calcThumbPosition = () => {
+	if (containerEl.value == null) {
+		thumbPosition.value = 0;
+	} else {
+		thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value;
+	}
+};
+watch([steppedRawValue, containerEl], calcThumbPosition);
+
+let ro: ResizeObserver | undefined;
+
+onMounted(() => {
+	ro = new ResizeObserver((entries, observer) => {
+		calcThumbPosition();
+	});
+	ro.observe(containerEl.value);
+});
+
+onUnmounted(() => {
+	if (ro) ro.disconnect();
+});
+
+const steps = computed(() => {
+	if (props.step) {
+		return (props.max - props.min) / props.step;
+	} else {
+		return 0;
+	}
+});
+
+const onMousedown = (ev: MouseEvent | TouchEvent) => {
+	ev.preventDefault();
+
+	const tooltipShowing = ref(true);
+	os.popup(defineAsyncComponent(() => import('@/components/ui/tooltip.vue')), {
+		showing: tooltipShowing,
+		text: computed(() => {
+			return props.textConverter(finalValue.value);
+		}),
+		targetElement: thumbEl,
+	}, {}, 'closed');
+
+	const style = document.createElement('style');
+	style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
+	document.head.appendChild(style);
+
+	const onDrag = (ev: MouseEvent | TouchEvent) => {
+		ev.preventDefault();
+		const containerRect = containerEl.value!.getBoundingClientRect();
+		const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX;
+		const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2));
+		rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value)));
+	};
+
+	let beforeValue = finalValue.value;
+
+	const onMouseup = () => {
+		document.head.removeChild(style);
+		tooltipShowing.value = false;
+		window.removeEventListener('mousemove', onDrag);
+		window.removeEventListener('touchmove', onDrag);
+		window.removeEventListener('mouseup', onMouseup);
+		window.removeEventListener('touchend', onMouseup);
+
+		// 値が変わってたら通知
+		if (beforeValue !== finalValue.value) {
+			emit('update:modelValue', finalValue.value);
+		}
+	};
+
+	window.addEventListener('mousemove', onDrag);
+	window.addEventListener('touchmove', onDrag);
+	window.addEventListener('mouseup', onMouseup, { once: true });
+	window.addEventListener('touchend', onMouseup, { once: true });
+};
 </script>
 
 <style lang="scss" scoped>