QSelect component
QSelect allows your user to select from a variety of options. Its properties and functionalities are similar to the ones from QInput, including label behavior and error handling.
Requirements
Type | Path / Version | Purpose | Optional |
---|---|---|---|
Styles | ../../assets/main.css | CSS Variables | No |
Functions | ../../use/uuid | Assign ids to items | No |
Components | ../../components/Form/QButton.vue | Full form example | Yes |
Usage
Import the following component/s:
import QSelect from '../../components/Form/QSelect.vue';
Placeholder prefix
QSelect uses the label as a first, inactive element in the options. In case the label alone is not enough, you can extend it with a prefix. Doing so makes the placeholder become lower case.
Example
<template>
<form @submit.prevent="onSubmit">
<q-select labelPrefix="Please " label="Number of attendees" :options="selectOptions" v-model="selectValue"></q-select>
<p>Output: {{ selectValue }}</p>
<q-button type="submit" label="Submit" />
</form>
</template>
<script setup>
import { ref } from 'vue';
const selectValue = ref(null);
const selectOptions = [
'One Visitor',
'Two Visitors',
'Three Visitors',
];
const onSubmit = () => alert(`${selectValue.value} will be attending`);
</script>
Bind objects
Beside binding an array of strings, you can also bind an array of objects. These have to include the following props:
value
(required) => what gets bound tov-model
key
(optional) => a:key
prop to identify the unique entrytext
(optional) => text to be shown instead of the valuedisabled
(optional) => whether option element isdisabled
or not
QSelect will then try the following:
- Create one option element for each
value
property and bind it. - If value does not exist, fall back to binding the whole object
- Try and bind the
key
property to the option element - If key does not exist, fall back to binding the
value
- Try and show the
text
property for each option - If text does not exist, fall back to binding the
value
Example
<template>
<form @submit.prevent="onSubmit">
<q-select labelPrefix="Please " label="Number of attendees" :options="selectOptionsText" v-model="selectValue"></q-select>
<p>Output: [ {{ selectValue }} ] visitors are attending</p>
<q-button type="submit" label="Submit" />
</form>
</template>
<script setup>
import { ref } from 'vue';
const selectValue = ref(null)
const selectOptionsText = [
{ key: 1, text: "One Visitor", value: 1 },
{ key: 2, text: "Two Visitors", value: 2, disabled: true },
{ key: 3, text: "Three visitors", value: 3 }
]
const onSubmit = () => alert(`${selectValue.value} will be attending`);
</script>
Required fields
See QInput@required-fields for behavior and customization
Example
<template>
<form @submit.prevent="onSubmit">
<q-select required requiredSign="(please select one)" label="Number of attendees" :options="selectOptions" v-model="selectValue"></q-select>
<p>Output: {{ selectValue }}</p>
<q-button type="submit" label="Submit" />
</form>
</template>
<script setup>
import { ref } from 'vue';
const selectValue = ref(null)
const selectOptions = [
'One Visitor',
'Two Visitors',
'Three Visitors',
];
const onSubmit = () => alert(`${selectValue.value} will be attending`);
</script>
Multiple values behavior
When declaring the multiple
HTML5 attribute, QSelect
will not consider all selected entries. While this behavior could be adjusted, I'd recommend to just use QCheckbox
whenever the selection of multiple elements is necessary
Full component's code
QSelect
<template>
<label v-if="label" :for="id" class="q-input-label">
{{ label }}
<span class="q-input-required-sign" v-if="required">
{{
requiredSign
}}
</span>
</label>
<select
class="q-input-base"
:class="{
'q-error': !!error,
}"
v-bind="{
...$attrs,
onChange: ($event) => $emit('update:modelValue', $event.target.value),
}"
:id="id"
:required="required"
:placeholder="labelPrefix ? labelPrefix + label.toLowerCase() : label"
:aria-label="label"
:aria-required="required"
:aria-describedby="error ? `${id}-error` : null"
:aria-invalid="error ? true : null"
>
<option
selected
disabled
aria-disabled
>{{ labelPrefix ? labelPrefix + label.toLowerCase() : label }}</option>
<option
v-for="option in options"
:value="option.value ? option.value : option"
:key="option.key ? option.key : option"
:selected="option === modelValue"
:aria-selected="option.text ? option.text : option.value ? option.value : option"
:disabled="option.disabled"
:aria-disabled="option.disabled"
>{{ option.text ? option.text : option.value ? option.value : option }}</option>
</select>
<small
v-if="error"
class="q-input-error-msg"
:id="`${id}-error`"
aria-live="assertive"
>{{ error }}</small>
</template>
<script setup>
import uuid from "../../use/uuid";
const id = uuid();
defineProps({
labelPrefix: {
type: String,
default: null,
},
label: {
type: String,
default: "",
},
options: {
type: Array,
required: true,
},
modelValue: {
type: [String, Number],
default: "",
},
error: {
type: String,
default: "",
},
required: {
type: Boolean,
default: false,
},
requiredSign: {
type: String,
default: "*",
},
});
</script>
<style scoped>
option {
background-color: var(--background-color-primary);
color: var(--text-color-primary);
}
.q-input-base,
.q-input-label {
display: block;
width: 100%;
font-size: var(--text-size-sm);
}
.q-input-label {
color: var(--accent-color-primary);
font-size: var(--text-size-sm);
font-weight: 600;
}
.q-input-required-sign {
color: var(--color-error);
}
.q-input-base {
background-color: transparent;
color: var(--text-color-primary);
caret-color: var(--text-color-primary);
border: none;
border-bottom: var(--gap-xxs) solid transparent;
padding: var(--gap-sm) var(--gap-xs);
margin: var(--gap-sm) 0;
}
.q-input-base:focus {
outline: none;
transition: var(--duration-quickest);
border-bottom: var(--gap-xxs) solid var(--accent-color-primary);
}
.q-input-base:focus.q-error {
border-bottom: var(--gap-xxs) solid var(--color-error);
}
.q-input-error-msg {
font-size: var(--text-xs);
color: var(--color-error);
}
</style>