From bc308b0f8a8bab2bdec34a064fc2c3ee2992073c Mon Sep 17 00:00:00 2001 From: J-Sek Date: Wed, 3 Sep 2025 10:38:38 +0200 Subject: [PATCH 1/2] fix(VTextarea): mask should not clip scrollbar --- .../src/components/VTextarea/VTextarea.sass | 6 ++++-- .../vuetify/src/components/VTextarea/VTextarea.tsx | 14 +++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/vuetify/src/components/VTextarea/VTextarea.sass b/packages/vuetify/src/components/VTextarea/VTextarea.sass index b9bce78586b..f97c74aa3e2 100644 --- a/packages/vuetify/src/components/VTextarea/VTextarea.sass +++ b/packages/vuetify/src/components/VTextarea/VTextarea.sass @@ -15,11 +15,13 @@ .v-field__input $a: calc((var(--v-field-padding-top, 0) + var(--v-input-padding-top, 0)) - 6px) $b: calc(var(--v-field-padding-top, 0) + var(--v-input-padding-top, 0) + 4px) + $c: calc(100% - var(--v-textarea-scroll-bar-width, 16px)) flex: 1 1 auto outline: none - -webkit-mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b) - mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b) + + -webkit-mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b), linear-gradient(to right, transparent, transparent $c, black $c) + mask-image: linear-gradient(to bottom, transparent, transparent $a, black $b), linear-gradient(to right, transparent, transparent $c, black $c) &.v-textarea__sizer visibility: hidden diff --git a/packages/vuetify/src/components/VTextarea/VTextarea.tsx b/packages/vuetify/src/components/VTextarea/VTextarea.tsx index c5b6d5db648..17510e28063 100644 --- a/packages/vuetify/src/components/VTextarea/VTextarea.tsx +++ b/packages/vuetify/src/components/VTextarea/VTextarea.tsx @@ -101,6 +101,7 @@ export const VTextarea = genericComponent()({ const vFieldRef = ref() const controlHeight = shallowRef('') const textareaRef = ref() + const scrollbarWidth = ref(0) const autocomplete = useAutocomplete(props) const isActive = computed(() => ( props.persistentPlaceholder || @@ -157,6 +158,12 @@ export const VTextarea = genericComponent()({ if (!props.autoGrow) rows.value = Number(props.rows) }) function calculateInputHeight () { + nextTick(() => { + if (!textareaRef.value) return + const { offsetWidth, clientWidth } = textareaRef.value + scrollbarWidth.value = Math.max(0, offsetWidth - clientWidth) + }) + if (!props.autoGrow) return nextTick(() => { @@ -232,7 +239,12 @@ export const VTextarea = genericComponent()({ }, props.class, ]} - style={ props.style } + style={[ + { + '--v-textarea-scroll-bar-width': convertToUnit(scrollbarWidth.value), + }, + props.style, + ]} { ...rootAttrs } { ...inputProps } centerAffix={ rows.value === 1 && !isPlainOrUnderlined.value } From 3d2919a408a14836542ac7116c5c0b1f57204251 Mon Sep 17 00:00:00 2001 From: J-Sek Date: Wed, 1 Oct 2025 13:33:53 +0200 Subject: [PATCH 2/2] fix: support Firefox & Zen --- packages/vuetify/src/components/VTextarea/VTextarea.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/vuetify/src/components/VTextarea/VTextarea.tsx b/packages/vuetify/src/components/VTextarea/VTextarea.tsx index 17510e28063..8746445e6f2 100644 --- a/packages/vuetify/src/components/VTextarea/VTextarea.tsx +++ b/packages/vuetify/src/components/VTextarea/VTextarea.tsx @@ -9,6 +9,7 @@ import { makeVFieldProps } from '@/components/VField/VField' import { makeVInputProps, VInput } from '@/components/VInput/VInput' // Composables +import { useDisplay } from '@/composables' import { makeAutocompleteProps, useAutocomplete } from '@/composables/autocomplete' import { useAutofocus } from '@/composables/autofocus' import { useFocus } from '@/composables/focus' @@ -102,6 +103,7 @@ export const VTextarea = genericComponent()({ const controlHeight = shallowRef('') const textareaRef = ref() const scrollbarWidth = ref(0) + const { platform } = useDisplay() const autocomplete = useAutocomplete(props) const isActive = computed(() => ( props.persistentPlaceholder || @@ -160,6 +162,10 @@ export const VTextarea = genericComponent()({ function calculateInputHeight () { nextTick(() => { if (!textareaRef.value) return + if (platform.value.firefox) { + scrollbarWidth.value = 12 + return + } const { offsetWidth, clientWidth } = textareaRef.value scrollbarWidth.value = Math.max(0, offsetWidth - clientWidth) })