QInput component

QInput is kept as simple as possible to allow for a variety of use cases. It defaults to 100% width and uses some basic aria attributes, including error handling.

HTML input types

An extensive list of HTML5 input elements can be found at the end of this page

Requirements

TypePath / VersionPurposeOptional
Styles../../assets/main.cssCSS VariablesNo
Functions../../use/uuidAssign ids to itemsNo

Usage

Import the following component/s:

import QInput from '../../components/Form/QInput.vue'

Basic use case

You can use v-model & label bindings on the component. The placeholder defaults to the label

Output:

Example

<template>
  <q-input label="Name" v-model="inputValue" />
  <p>Output: {{inputValue}}</p>
</template>

<script setup>
import { ref } from 'vue';
const inputValue = ref('');
</script>

Placeholder prefix

In case the label alone is not enough, you can extend it with a prefix. Doing so makes the placeholder become lower case

Output:

Example

<template>
  <q-input labelPrefix="Type in your " label="Name" v-model="inputValue" />
  <p>Output: {{inputValue}}</p>
</template>

<script setup>
import { ref } from 'vue';
const inputValue = ref('');
</script>

Required fields

Adding required as an attribute also adds a requiredSign. You can optionally customize its content.

Default ( * )

Output:

Custom sign ( required )

Output:

Example

<template>
  <form @submit.prevent="onSubmit">
    <q-input labelPrefix="Type in your " required requiredSign="(required)" label="Name" v-model="inputValue" />
    <p>Output: {{inputValue}}</p>
  </form>
</template>

<script setup>
import { ref } from 'vue';
const inputValue = ref('');
const onSubmit = () => alert(`Your input: ${inputValue.value}`);
</script>

Suggestions (datalist)

Output:

Example

<template>
  <form @submit.prevent="onSubmit">
    <q-input labelPrefix="Type in your " required requiredSign="(required)" label="Name" v-model="inputValue" />
    <p>Output: {{inputValue}}</p>
  </form>
</template>

<script setup>
import { ref } from 'vue';
const inputValue = ref('');
const inputOptions = [
  'John Doe',
  'Eric Sutherland',
  'Jane Doenym',
];
const onSubmit = () => alert(`Your input: ${inputValue.value}`);
</script>

Error handling

Errors are rendered right below the input element. The form below will toggle errors when submitted to give you an idea of how they look like

Error:

Example

<template>
  <form @submit.prevent="onError">
    <q-input :error="inputError" labelPrefix="Type in your " label="Name" v-model="inputValue" />
    <p>Erorr: {{inputError}}</p>
  </form>
</template>

<script setup>
import { ref } from 'vue';
const inputError = ref('');
const onError = () => (inputError.value = inputError.value === "" ? "An error has occured" : "");
</script>

Full component's code

QInput

<template>
  <label v-if="label" :for="id" class="q-input-label">
    {{ label }}
    <span class="q-input-required-sign" v-if="required">{{ requiredSign }}</span>
  </label>
  <input
    :list="options ? `${id}-options` : null"
    class="q-input-base"
    :class="{
      'q-error': !!error,
    }"
    v-bind="$attrs"
    @input="$emit('update:modelValue', $event.target.value)"
    :value="modelValue"
    :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"
  />
  <datalist :id="`${id}-options`">
    <option v-for="option in options" :value="option.value ? option.value : option" :key="option"></option>
  </datalist>

  <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,
  },
  options: {
    type: Array,
  },
  modelValue: {
    type: [String, Number],
  },
  error: {
    type: String,
  },
  required: {
    type: Boolean,
    default: false,
  },
  requiredSign: {
    type: String,
    default: "*",
  },
})
</script>

<style scoped>
datalist {
  width: 100%;
  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>

List of input types

Source: W3schools

TODO: Add a list element here