WithFloatingLabel
带浮动标签和清除按钮的输入框组件。
简介
MWithFloatingLabel 是一个带有浮动标签效果的输入框组件。标签在输入框为空时居中显示为占位符,聚焦或有内容时自动上浮,同时内置清除按钮,有内容时右侧自动显示。
用法
标签在空值时居中显示,聚焦或有内容时自动上浮:
<script setup lang="ts">
const value = ref("test@example.com")
</script>
<template>
<MWithFloatingLabel v-model="value" label="邮箱地址" />
</template>
leadingIcon 前置图标
通过 leadingIcon 为输入框添加前置图标:
<template>
<MWithFloatingLabel label="用户名" leading-icon="i-lucide-user" />
</template>
size 尺寸
通过 size 切换输入框与标签尺寸:
<template>
<MWithFloatingLabel label="尺寸演示" size="md" />
</template>
clearButtonProps 清除按钮
<script setup lang="ts">
const value = ref('test@example.com')
</script>
<template>
<MWithFloatingLabel
v-model="value"
label="邮箱地址"
:ui="{ label: 'text-warning' }"
:clear-button-props="{ color: 'error', icon: 'i-lucide-x' }"
/>
</template>
示例
清除事件
通过 @clear 事件监听清除操作:
<script setup lang="ts">
const toast = useToast()
const email = ref('user@example.com')
function handleClear() {
toast.add({
title: '已清除',
description: '输入内容已清空',
color: 'neutral'
})
}
</script>
<template>
<MWithFloatingLabel v-model="email" label="邮箱地址" leading-icon="i-lucide-mail" @clear="handleClear" />
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
label | string | |
size | "xs" | "sm" | "md" | "lg" | "xl" | |
clearButtonProps | ButtonProps | |
id | string | |
name | string | |
type | "number" | "color" | "button" | "checkbox" | "date" | "datetime-local" | "email" | "file" | "hidden" | "image" | "month" | "password" | "radio" | "range" | "reset" | "search" | "submit" | "tel" | "text" | "time" | "url" | "week" | string & {} | |
placeholder | stringThe placeholder text when the input is empty. | |
color | 'primary' | "primary" | "secondary" | "info" | "success" | "warning" | "error" | "important" | "neutral" |
variant | 'outline' | "outline" | "soft" | "subtle" | "ghost" | "none" |
autocomplete | string & {} | "on" | "off" | |
autofocusDelay | number | |
defaultValue | T | |
modelModifiers | ModelModifiers | |
icon | anyDisplay an icon based on the | |
avatar | AvatarPropsDisplay an avatar on the left side. | |
leadingIcon | anyDisplay an icon on the left side. | |
trailingIcon | anyDisplay an icon on the right side. | |
loadingIcon | appConfig.ui.icons.loading | anyThe icon when the |
list | string | |
max | string | number | |
maxlength | string | number | |
min | string | number | |
minlength | string | number | |
pattern | string | |
readonly | false | true | "true" | "false" | |
step | string | number | |
modelValue | T | |
required | boolean | |
autofocus | boolean | |
disabled | boolean | |
highlight | booleanHighlight the ring color like a focus state. | |
fixed | booleanKeep the mobile text size on all breakpoints. | |
leading | booleanWhen | |
trailing | booleanWhen | |
loading | booleanWhen | |
ui | Record<string, ClassNameValue> & { root?: SlotClass; base?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; leadingAvatar?: SlotClass; leadingAvatarSize?: SlotClass; trailing?: SlotClass; trailingIcon?: SlotClass; label?: SlotClass; labelText?: SlotClass; } |
Emits
| Event | Type |
|---|---|
update:modelValue | [value: T] |
blur | [event: FocusEvent] |
change | [event: Event] |
clear | [] |
Slots
| Slot | Type |
|---|---|
leading | { ui: { root: (props?: Record<string, any>) => string; base: (props?: Record<string, any>) => string; leading: (props?: Record<string, any>) => string; leadingIcon: (props?: Record<string, any>) => string; leadingAvatar: (props?: Record<string, any>) => string; leadingAvatarSize: (props?: Record<string, any>) => string; trailing: (props?: Record<string, any>) => string; trailingIcon: (props?: Record<string, any>) => string; }; } |
Theme
app.config.ts
export default defineAppConfig({
ui: {
withFloatingLabel: {
slots: {
base: 'peer',
trailing: 'pe-1',
label: 'pointer-events-none absolute -top-2.5 px-1.5 transition-all text-highlighted text-xs font-medium peer-focus:-top-2.5 peer-focus:text-highlighted peer-focus:text-xs peer-focus:font-medium peer-placeholder-shown:text-dimmed peer-placeholder-shown:font-normal peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-focus:translate-y-0',
labelText: 'inline-flex bg-default px-1'
},
variants: {
size: {
xs: {
label: 'peer-placeholder-shown:text-xs'
},
sm: {
label: 'peer-placeholder-shown:text-xs'
},
md: {
label: 'peer-placeholder-shown:text-sm'
},
lg: {
label: 'peer-placeholder-shown:text-sm'
},
xl: {
label: 'peer-placeholder-shown:text-base'
}
},
hasLeading: {
true: {},
false: {
label: 'left-0'
}
}
},
compoundVariants: [
{
size: 'xs',
hasLeading: true,
class: {
label: 'left-5'
}
},
{
size: 'sm',
hasLeading: true,
class: {
label: 'left-6'
}
},
{
size: 'md',
hasLeading: true,
class: {
label: 'left-7'
}
},
{
size: 'lg',
hasLeading: true,
class: {
label: 'left-8'
}
},
{
size: 'xl',
hasLeading: true,
class: {
label: 'left-9'
}
}
],
defaultVariants: {
size: 'md',
hasLeading: false
}
}
}
})
Changelog
No recent changes