Categories
Quasar

Developing Vue Apps with the Quasar Library — Form Validation and Custom Form Fields

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Form Validation

We can control form validation within the component object.

To do this, we assign a ref to our q-form and then call the methods that are exposed:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-form
            @submit="onSubmit"
            @reset="onReset"
            class="q-gutter-md"
            ref="form"
          >
            <q-input
              filled
              v-model="name"
              label="Your name *"
              hint="Name"
              lazy-rules
              :rules="[ val => val && val.length > 0 || 'Please type something']"
            >
            </q-input>

            <q-input
              filled
              type="number"
              v-model="age"
              label="Your age *"
              lazy-rules
              :rules="[
                val => val !== null && val !== '' || 'Please type your age',
                val => val > 0 && val < 130 || 'Please type a real age'
              ]"
            >
            </q-input>

            <div>
              <q-btn label="Submit" type="submit" color="primary"></q-btn>
              <q-btn
                label="Reset"
                type="reset"
                color="primary"
                flat
                class="q-ml-sm"
              ></q-btn>
            </div>
          </q-form>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          name: "",
          age: ""
        },
        methods: {
          async onSubmit() {
            const sucess = await this.$refs.form.validate();
            if (!success) {
              return;
            }
            this.$q.notify({
              color: "green-4",
              textColor: "white",
              icon: "cloud_done",
              message: "Submitted"
            });
          },
          onReset() {
            this.name = null;
            this.age = null;
            this.$refs.form.resetValidation();
          }
        }
      });
    </script>
  </body>
</html>

We assign the form ref to the q-form component.

In the onSubmit method, we use the ref by calling the validate method to validate the form.

And then we call resetValidation to reset validation in the onReset method.

Form Field

We can use the q-field component to create our own form field.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-field label="Standard" stack-label>
            <template v-slot:control>
              <div class="self-center full-width no-outline" tabindex="0">
                Field content
              </div>
            </template>
          </q-field>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {}
      });
    </script>
  </body>
</html>

We add the q-field component and populate its control slot to add the field with the placeholder being the content of the control slot.

Form Field Color

We can set the color of form fields.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-field
            color="lime-11"
            bg-color="green"
            filled
            label="Label"
            stack-label
          >
            <template v-slot:prepend>
              <q-icon name="event"></q-icon>
            </template>
            <template v-slot:control>
              <div class="self-center full-width no-outline" tabindex="0">
                {{text}}
              </div>
            </template>
          </q-field>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          text: "abc"
        }
      });
    </script>
  </body>
</html>

to add the bg-color prop to change the background color of the form field.

Conclusion

We can add form validation and custom form fields into our Vue app with Quasar.

Categories
Quasar

Developing Vue Apps with the Quasar Library — File Type and Size Validation and Forms

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

File Type and Size Validation

We can validate file type and size with Quasar’a file picker in our Vue app.

To add it, we write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            style="max-width: 300px;"
            v-model="filesMaxSize"
            filled
            label="Filtered"
            multiple
            :filter="checkFileSize"
            @rejected="onRejected"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: [],
          filesMaxSize: null,
          filesPng: null
        },
        methods: {
          checkFileSize(files) {
            return files.filter((file) => file.size < 2048);
          },
          onRejected(rejectedEntries) {
            this.$q.notify({
              type: "negative",
              message: `${rejectedEntries.length} file(s) did not pass validation constraints`
            });
          }
        }
      });
    </script>
  </body>
</html>

We add the checkFileSize method to return files that are less than the given size in bytes.

files has an array of files.

size has the file size.

onRejected lets us display a message if we have any files that don’t meet the requirements.

rejectedEntries has an array of rejected files.

We set the filter prop to the checkFileSize method.

onRejected is the value of the rejected listener.

We can check file types of the selected files with:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            style="max-width: 300px;"
            v-model="filesMaxSize"
            filled
            label="Filtered"
            multiple
            :filter="checkFileType"
            @rejected="onRejected"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: [],
          filesMaxSize: null,
          filesPng: null
        },
        methods: {
          checkFileType(files) {
            return files.filter((file) => file.type === "image/png");
          },
          onRejected(rejectedEntries) {
            this.$q.notify({
              type: "negative",
              message: `${rejectedEntries.length} file(s) did not pass validation constraints`
            });
          }
        }
      });
    </script>
  </body>
</html>

checkFileType lets us check the file type. We get the type property of each file and compare it.

Forms

We can add forms with the q-form component.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-form @submit="onSubmit" @reset="onReset" class="q-gutter-md">
            <q-input
              filled
              v-model="name"
              label="Your name *"
              hint="Name"
              lazy-rules
              :rules="[ val => val && val.length > 0 || 'Please type something']"
            >
            </q-input>

            <q-input
              filled
              type="number"
              v-model="age"
              label="Your age *"
              lazy-rules
              :rules="[
                val => val !== null && val !== '' || 'Please type your age',
                val => val > 0 && val < 130 || 'Please type a real age'
              ]"
            >
            </q-input>

            <div>
              <q-btn label="Submit" type="submit" color="primary"></q-btn>
              <q-btn
                label="Reset"
                type="reset"
                color="primary"
                flat
                class="q-ml-sm"
              ></q-btn>
            </div>
          </q-form>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          name: "",
          age: ""
        },
        methods: {
          onSubmit() {
            this.$q.notify({
              color: "green-4",
              textColor: "white",
              icon: "cloud_done",
              message: "Submitted"
            });
          },
          onReset() {
            this.name = null;
            this.age = null;
          }
        }
      });
    </script>
  </body>
</html>

We add the q-input components inside our q-form with the rules prop.

The rules are for validating the inputs.

When we click Submit, the rules will be checked.

They return true if the value is valid or an error message otherwise.

We also add a q-btn with type reset to let us reset the form values.

We listen to the submit and reset events with the methods used as handlers for each event.

Conclusion

We can add forms and file size and type validation into our Vue app with Quasar.

Categories
Quasar

Developing Vue Apps with the Quasar Library — File Upload Progress

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

File Upload Progress

We can add file upload progress display to the file picker with the q-file component.

To do this, we write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            :value="files"
            @input="updateFiles"
            label="Pick files"
            outlined
            multiple
            :clearable="!isUploading"
            style="max-width: 400px;"
          >
            <template v-slot:file="{ index, file }">
              <q-chip
                class="full-width q-my-xs"
                :removable="isUploading && uploadProgress[index].percent < 1"
                square
              >
                <q-linear-progress
                  class="absolute-full full-height"
                  :value="uploadProgress[index].percent"
                  :color="uploadProgress[index].color"
                  track-color="grey-2"
                >
                </q-linear-progress>

                <q-avatar>
                  <q-icon :name="uploadProgress[index].icon"></q-icon>
                </q-avatar>

                <div class="ellipsis relative-position">
                  {{ file.name }}
                </div>

                <q-tooltip>
                  {{ file.name }}
                </q-tooltip>
              </q-chip>
            </template>

            <template v-slot:after v-if="canUpload">
              <q-btn
                color="primary"
                dense
                icon="cloud_upload"
                round
                @click="upload"
                :disable="!canUpload"
                :loading="isUploading"
              >
              </q-btn>
            </template>
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: null,
          uploadProgress: [],
          uploading: null,
          isUploading: false
        },
        computed: {
          isUploading() {
            return this.uploading !== null;
          },

          canUpload() {
            return this.files !== null;
          }
        },
        methods: {
          updateFiles(files) {
            this.files = files;
            this.uploadProgress = (files || []).map((file) => ({
              error: false,
              color: "green-1",
              percent: 0,
              icon:
                file.type.indexOf("video/") === 0
                  ? "movie"
                  : file.type.indexOf("image/") === 0
                  ? "photo"
                  : file.type.indexOf("audio/") === 0
                  ? "audiotrack"
                  : "insert_drive_file"
            }));
          },
          upload() {
            clearTimeout(this.uploading);

            const allDone = this.uploadProgress.every(
              (progress) => progress.percent === 1
            );

            this.uploadProgress = this.uploadProgress.map((progress) => ({
              ...progress,
              error: false,
              color: "green-2",
              percent: allDone === true ? 0 : progress.percent
            }));

            this.__updateUploadProgress();
          },

          __updateUploadProgress() {
            let done = true;

            this.uploadProgress = this.uploadProgress.map((progress) => {
              if (progress.percent === 1 || progress.error === true) {
                return progress;
              }

              const percent = Math.min(
                1,
                progress.percent + Math.random() / 10
              );
              const error = percent < 1 && Math.random() > 0.95;

              if (error === false && percent < 1 && done === true) {
                done = false;
              }

              return {
                ...progress,
                error,
                color: error === true ? "red-2" : "green-2",
                percent
              };
            });

            this.uploading =
              done !== true
                ? setTimeout(this.__updateUploadProgress, 300)
                : null;
          }
        },
        beforeDestroy() {
          clearTimeout(this.uploading);
        }
      });
    </script>
  </body>
</html>

We listen for file changes with the updateFiles method.

In the method, we get the files from the parameter and then call map to return an array of object to display the icons we want.

The upload method is called when we click on the button on the right.

We get the progress from the uploadProgress property and then update it by getting the progress from the progress.percent property.

We set the percent from in the method and set the as the value of the value prop in the q-linear-progress component to display the progress.

Conclusion

We can add a progress bar to the file input to show file upload progress with Quasar.

Categories
Quasar

Developing Vue Apps with the Quasar Library — File Input Options

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Clearable File Input

We can add a clearable file input with the clearable prop:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            clearable
            standout
            v-model="model"
            label="Label"
            counter
            clearable
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          model: undefined
        }
      });
    </script>
  </body>
</html>

Disable and Readonly File Inputs

We can add the disable and readonly prop to disable interaction with the file input.

disable changes the styles but readonly doesn’t.

For instance, we can use it by writing:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="[https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons](https://medium.com/r/?url=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DRoboto%3A100%2C300%2C400%2C500%2C700%2C900%7CMaterial%2BIcons)"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="[https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css](https://medium.com/r/?url=https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fquasar%401.12.13%2Fdist%2Fquasar.min.css)"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="[https://cdn.jsdelivr.net/npm/vue@](https://medium.com/r/?url=https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fvue%40)^2.0.0/dist/vue.min.js"></script>
    <script src="[https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js](https://medium.com/r/?url=https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fquasar%401.12.13%2Fdist%2Fquasar.umd.min.js)"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            disable
            filled
            v-model="model"
            hint="Disable"
            style="width: 250px;"
          >
          </q-file>

          <q-file
            readonly
            filled
            v-model="model"
            hint="Readonly"
            style="width: 250px;"
          >
          </q-file>

          <q-file
            disable
            readonly
            filled
            v-model="model"
            hint="Disable and readonly"
            style="width: 250px;"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          model: undefined
        }
      });
    </script>
  </body>
</html>

Select Mutliple Files

We can let users select multiple files with the multiple prop:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            v-model="files"
            label="Pick files"
            filled
            multiple
            style="max-width: 300px;"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: undefined
        }
      });
    </script>
  </body>
</html>

Appending Files

By default, the file input resets the selected files each time we select files.

With the append prop, we can let users keep adding files:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            v-model="files"
            label="Pick files"
            filled
            multiple
            append
            style="max-width: 300px;"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: undefined
        }
      });
    </script>
  </body>
</html>

File Input Counter

The file input comes with a counter for the number of files selected and the total size of the selected files.

We just have to add the counter prop to enable it:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            v-model="files"
            label="Pick files"
            filled
            counter
            style="max-width: 300px;"
          >
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          files: undefined
        }
      });
    </script>
  </body>
</html>

Conclusion

We can add file inputs with various options into our Vue app with Quasar.

Categories
Quasar

Developing Vue Apps with the Quasar Library — File Picker

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

File Picker

Quasar comes with a file picker component.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            rounded
            outlined
            v-model="model"
            label="Choose a file"
          ></q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          model: undefined
        }
      });
    </script>
  </body>
</html>

to add a file input.

The q-file component lets us add a file input easily.

It binds the selected file to a reactive property with v-model .

rounded and outlined are props for styles.

Other props to change styling include square , filled , standout and borderless .

label has the placeholder for the file input.

File Input Decorators

We can add various icons to file inputs.

For example, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            rounded
            outlined
            bottom-slots
            v-model="model"
            label="Label"
            counter
            max-files="12"
          >
            <template v-slot:before>
              <q-icon name="attachment"></q-icon>
            </template>

            <template v-slot:append>
              <q-icon
                v-if="model !== null"
                name="close"
                @click.stop="model = null"
                class="cursor-pointer"
              ></q-icon>
              <q-icon name="search" @click.stop></q-icon>
            </template>

            <template v-slot:hint>
              Field hint
            </template>
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          model: undefined
        }
      });
    </script>
  </body>
</html>

to add a file input with various icons.

The before slot lets us add icons to the left side of the file input outside it.

append lets us add content inside the input on the right side.

We can populate the hint slot and add the bottoms-slots property to add text below the file input.

File Input Color

To change colors, we can add the label-color , bg-color , and color props:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout
        view="lHh Lpr lFf"
        container
        style="height: 100vh;"
        class="shadow-2 rounded-borders"
      >
        <div class="q-pa-md">
          <q-file
            clearable
            label-color="yellow"
            bg-color="green"
            standout
            bottom-slots
            v-model="model"
            label="Label"
            counter
          >
            <template v-slot:prepend>
              <q-icon color="yellow" name="attach_file"></q-icon>
            </template>
            <template v-slot:append>
              <q-icon color="yellow" name="favorite"></q-icon>
            </template>

            <template v-slot:hint>
              Field hint
            </template>
          </q-file>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          model: undefined
        }
      });
    </script>
  </body>
</html>

We can change the background color with the bg-color prop.

The label-color prop changes the label color

And the color prop changes the icon color.

Comclusion

We can add a file input into our Vue app with the Quasar library.