custom chevron on selects with 16px right inset

Native <select> chevrons render at varying offsets across browsers.
Replaced them with `appearance-none` + an absolute-positioned
chevron-down Icon at right-4 (16px) so the gap between the chevron
and the right border is consistent. Applied to RegisterPage's
salutation select and ShippingStep's shipping/billing country selects.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-05-03 18:56:24 +01:00
parent 0bf8a32d97
commit 4ed021280a
10 changed files with 58 additions and 32 deletions

View File

@@ -11,6 +11,7 @@ import Navbar from '@/design-system/components/Navbar.vue'
import Footer from '@/design-system/components/Footer.vue'
import Input from '@/design-system/components/Input.vue'
import Button from '@/design-system/components/Button.vue'
import Icon from '@/design-system/components/Icon.vue'
import { products, register } from '@/api/index.js'
import { useCartStore } from '@/stores/cart.js'
import { useI18n } from '@/i18n/index.js'
@@ -125,15 +126,23 @@ onBeforeUnmount(() => {
<label class="text-[11px] font-bold uppercase tracking-eyebrow text-muted">
{{ t('checkout.field.salutation') }}
</label>
<select
v-model="salutation"
class="w-full rounded-sm border border-line bg-paper px-4 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
>
<option value="">{{ t('checkout.field.salutation.placeholder') }}</option>
<option value="frau">{{ t('checkout.field.salutation.frau') }}</option>
<option value="herr">{{ t('checkout.field.salutation.herr') }}</option>
<option value="divers">{{ t('checkout.field.salutation.divers') }}</option>
</select>
<div class="relative">
<select
v-model="salutation"
class="appearance-none w-full rounded-sm border border-line bg-paper pl-4 pr-10 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
>
<option value="">{{ t('checkout.field.salutation.placeholder') }}</option>
<option value="frau">{{ t('checkout.field.salutation.frau') }}</option>
<option value="herr">{{ t('checkout.field.salutation.herr') }}</option>
<option value="divers">{{ t('checkout.field.salutation.divers') }}</option>
</select>
<Icon
name="chevron-down"
:size="18"
:stroke-width="2"
class="absolute right-4 top-1/2 -translate-y-1/2 text-muted pointer-events-none"
/>
</div>
</div>
<div class="grid gap-5 md:grid-cols-2">

View File

@@ -8,6 +8,7 @@ import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import Input from '@/design-system/components/Input.vue'
import Button from '@/design-system/components/Button.vue'
import Icon from '@/design-system/components/Icon.vue'
import { useCheckoutStore } from '@/stores/checkout.js'
import { useI18n } from '@/i18n/index.js'
@@ -77,14 +78,22 @@ function onSubmit() {
<label class="text-[11px] font-bold uppercase tracking-eyebrow text-muted">
{{ t('checkout.field.country') }}<span class="text-danger"> *</span>
</label>
<select
:value="checkout.shippingAddress.country"
required
class="w-full rounded-sm border border-line bg-paper px-4 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
@change="checkout.updateShipping({ country: $event.target.value })"
>
<option v-for="c in countries" :key="c.code" :value="c.code">{{ c.label }}</option>
</select>
<div class="relative">
<select
:value="checkout.shippingAddress.country"
required
class="appearance-none w-full rounded-sm border border-line bg-paper pl-4 pr-10 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
@change="checkout.updateShipping({ country: $event.target.value })"
>
<option v-for="c in countries" :key="c.code" :value="c.code">{{ c.label }}</option>
</select>
<Icon
name="chevron-down"
:size="18"
:stroke-width="2"
class="absolute right-4 top-1/2 -translate-y-1/2 text-muted pointer-events-none"
/>
</div>
</div>
<Input
:model-value="checkout.shippingAddress.phone"
@@ -142,14 +151,22 @@ function onSubmit() {
<label class="text-[11px] font-bold uppercase tracking-eyebrow text-muted">
{{ t('checkout.field.country') }}<span class="text-danger"> *</span>
</label>
<select
:value="checkout.billingAddress.country"
required
class="w-full rounded-sm border border-line bg-paper px-4 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
@change="checkout.updateBilling({ country: $event.target.value })"
>
<option v-for="c in countries" :key="c.code" :value="c.code">{{ c.label }}</option>
</select>
<div class="relative">
<select
:value="checkout.billingAddress.country"
required
class="appearance-none w-full rounded-sm border border-line bg-paper pl-4 pr-10 py-3 text-[15px] text-ink transition-colors duration-base focus:outline-none focus:border-brand"
@change="checkout.updateBilling({ country: $event.target.value })"
>
<option v-for="c in countries" :key="c.code" :value="c.code">{{ c.label }}</option>
</select>
<Icon
name="chevron-down"
:size="18"
:stroke-width="2"
class="absolute right-4 top-1/2 -translate-y-1/2 text-muted pointer-events-none"
/>
</div>
</div>
<Input
:model-value="checkout.billingAddress.phone"