Categories
Vuetify

Vuetify — Nested Dialogs

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Loader Dialog

We can create a loader dialog to show a progress bar inside it.

To do that, we write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <div class="text-center">
          <v-btn
            :disabled="dialog"
            :loading="dialog"
            class="white--text"
            color="purple darken-2"
            @click="dialog = true"
          >Start loading</v-btn>
          <v-dialog v-model="dialog" hide-overlay persistent width="300">
            <v-card color="primary" dark>
              <v-card-text>
                Please wait
                <v-progress-linear indeterminate color="white" class="mb-0"></v-progress-linear>
              </v-card-text>
            </v-card>
          </v-dialog>
        </div>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
  }),
  watch: {
    dialog(val) {
      if (!val) {
        return;
      }
      setTimeout(() => {
        this.dialog = false;
      }, 5000);
    },
  },
};
</script>

We added a dialog that shows a progress bar with the v-progress-linear component,

The indeterminate prop makes the progress bar move until the dialog is dismissed.

Nested Dialogs

We can open dialog boxes within another dialog.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <div>
          <v-row justify="center">
            <v-btn color="primary" class="ma-2" dark @click="dialog = true">Open Dialog 1</v-btn>
            <v-btn color="primary" class="ma-2" dark @click="dialog2 = true">Open Dialog 2</v-btn>
            <v-btn color="primary" class="ma-2" dark @click="dialog3 = true">Open Dialog 3</v-btn>
            <v-menu bottom offset-y>
              <template v-slot:activator="{ on, attrs }">
                <v-btn class="ma-2" v-bind="attrs" v-on="on">A Menu</v-btn>
              </template>
            </v-menu>
            <v-dialog
              v-model="dialog"
              fullscreen
              hide-overlay
              transition="dialog-bottom-transition"
              scrollable
            >
              <v-card tile>
                <v-card-text>
                  <v-btn color="primary" dark class="ma-2" @click="dialog2 = !dialog2">Open Dialog 2</v-btn>
                  <v-list three-line subheader>
                    <v-subheader>User Controls</v-subheader>
                  </v-list>
                </v-card-text>

                <div style="flex: 1 1 auto;"></div>
              </v-card>
            </v-dialog>

            <v-dialog v-model="dialog2" max-width="500px">
              <v-card>
                <v-card-title>Dialog 2</v-card-title>
                <v-card-text>
                  <v-btn color="primary" dark @click="dialog3 = !dialog3">Open Dialog 3</v-btn>
                </v-card-text>
                <v-card-actions>
                  <v-btn color="primary" text @click="dialog2 = false">Close</v-btn>
                </v-card-actions>
              </v-card>
            </v-dialog>
            <v-dialog v-model="dialog3" max-width="500px">
              <v-card>
                <v-card-title>
                  <span>Dialog 3</span>
                  <v-spacer></v-spacer>
                  <v-menu bottom left>
                    <template v-slot:activator="{ on, attrs }">
                      <v-btn icon v-bind="attrs" v-on="on">
                        <v-icon>mdi-dots-vertical</v-icon>
                      </v-btn>
                    </template>
                  </v-menu>
                </v-card-title>
                <v-card-actions>
                  <v-btn color="primary" text @click="dialog3 = false">Close</v-btn>
                </v-card-actions>
              </v-card>
            </v-dialog>
          </v-row>
        </div>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
    dialog2: false,
    dialog3: false,
    notifications: false,
    sound: true,
    widgets: false,
  }),
};
</script>

to show dialog boxes with buttons to open other dialog boxes.

They are all created with the v-dialog component.

Conclusion

We can add a dialog box to show a progress bar or other dialog boxes with Vuetify.

Categories
Vuetify

Vuetify — Dialog

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Modal

We can create a modal dialog with the persistent prop.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-row justify="center">
          <v-dialog v-model="dialog" persistent max-width="290">
            <template v-slot:activator="{ on, attrs }">
              <v-btn color="primary" dark v-bind="attrs" v-on="on">Open Dialog</v-btn>
            </template>
            <v-card>
              <v-card-title class="headline">Title</v-card-title>
              <v-card-text>Lorem ipsum.</v-card-text>
              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="green darken-1" text @click="dialog = false">Cancel</v-btn>
                <v-btn color="green darken-1" text @click="dialog = false">OK</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-row>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
  }),
};
</script>

We have the persistent prop on the v-dialog to make it closeable only with the buttons inside.

Scrollable

To make a dialog scrollable, we just add a scrollable prop.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-row justify="center">
          <v-dialog v-model="dialog" scrollable max-width="290">
            <template v-slot:activator="{ on, attrs }">
              <v-btn color="primary" dark v-bind="attrs" v-on="on">Open Dialog</v-btn>
            </template>
            <v-card>
              <v-card-title>Select Country</v-card-title>
              <v-divider></v-divider>
              <v-card-text style="height: 300px;">
                <v-radio-group v-model="country" column>
                  <v-radio :label="c" :value="c" v-for="(c, i) of countries" :key="i"></v-radio>
                </v-radio-group>
              </v-card-text>
              <v-spacer></v-spacer>
              <v-card-actions>
                <v-btn color="green darken-1" text @click="dialog = false">Cancel</v-btn>
                <v-btn color="green darken-1" text @click="dialog = false">OK</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-row>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
    country: "",
    countries: [
      "Afghanistan",
      "Albania",
      "Algeria",
      "American Samoa",
      "Andorra",
      "Angola",
      "Anguilla",
      "Antarctica",
      "Antigua and Barbuda",
      "Argentina",
      "Armenia",
      "Aruba",
      "Australia",
      "Austria",
      "Azerbaijan",
    ],
  }),
};
</script>

We display a radio button group that overflows the v-card-text container.

So we add the scrollable prop to the v-dialog to make the radio button group scrollable.

Overflowed

If the modal doesn’t fit the available window space, then the container will be scrolled.

Form

We can add a form inside the v-dialog component.

For instance, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-row justify="center">
          <v-dialog v-model="dialog" persistent max-width="600px">
            <template v-slot:activator="{ on, attrs }">
              <v-btn color="primary" dark v-bind="attrs" v-on="on">Open Dialog</v-btn>
            </template>
            <v-card>
              <v-card-title>
                <span class="headline">User Profile</span>
              </v-card-title>
              <v-card-text>
                <v-container>
                  <v-row>
                    <v-col cols="12" sm="6" md="4">
                      <v-text-field label="first name*" required></v-text-field>
                    </v-col>
                    <v-col cols="12" sm="6" md="4">
                      <v-text-field label="middle name" hint="middle name"></v-text-field>
                    </v-col>
                    <v-col cols="12" sm="6" md="4">
                      <v-text-field label="last name*" hint="last name" persistent-hint required></v-text-field>
                    </v-col>
                    <v-col cols="12">
                      <v-text-field label="Email*" required></v-text-field>
                    </v-col>
                    <v-col cols="12">
                      <v-text-field label="Password*" type="password" required></v-text-field>
                    </v-col>
                    <v-col cols="12">
                      <v-select :items="['0-17', '18-29', '30-54', '54+']" label="Age*" required></v-select>
                    </v-col>
                  </v-row>
                </v-container>
                <small>*required field</small>
              </v-card-text>
              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="blue darken-1" text @click="dialog = false">Close</v-btn>
                <v-btn color="blue darken-1" text @click="dialog = false">Save</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-row>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
  }),
};
</script>

to add a form inside the v-dialog .

This way, we’ll see the form when we open the dialog.

Conclusion

We can create a dialog with various kinds of content and behavior with Vuetify.

Categories
Vuetify

Vuetify — Expandable Chips and Dialogs

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Expandable Chips

A chip can be combined with the v-menu to enable a set of actions for a chip.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-card max-width="400" class="mx-auto">
          <v-row class="px-6 py-3" align="center">
            <span class="mr-4">To</span>
            <v-menu v-model="menu" bottom right transition="scale-transition" origin="top left">
              <template v-slot:activator="{ on }">
                <v-chip pill v-on="on">
                  <v-avatar left>
                    <v-img src="https://cdn.vuetifyjs.com/images/john.png"></v-img>
                  </v-avatar>John Leider
                </v-chip>
              </template>
              <v-card width="300">
                <v-list dark>
                  <v-list-item>
                    <v-list-item-avatar>
                      <v-img src="https://cdn.vuetifyjs.com/images/john.png"></v-img>
                    </v-list-item-avatar>
                    <v-list-item-content>
                      <v-list-item-title>John Smith</v-list-item-title>
                      <v-list-item-subtitle>john@smith.com</v-list-item-subtitle>
                    </v-list-item-content>
                    <v-list-item-action>
                      <v-btn icon @click="menu = false">
                        <v-icon>mdi-close-circle</v-icon>
                      </v-btn>
                    </v-list-item-action>
                  </v-list-item>
                </v-list>
                <v-list>
                  <v-list-item @click="() => {}">
                    <v-list-item-action>
                      <v-icon>mdi-briefcase</v-icon>
                    </v-list-item-action>
                    <v-list-item-subtitle>john@gmail.com</v-list-item-subtitle>
                  </v-list-item>
                </v-list>
              </v-card>
            </v-menu>
          </v-row>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    menu: false,
  }),
};
</script>

We have the v-menu that wraps outside the v-chip .

The v-chip has some text and an avatar.

Also, the v-list-item has the list that we show when we click on the chip.

The v-on="on" directive lets us toggle the menu since on includes the click listener.

Also, we have a close circle button to set menu to false when we click it.

This way, the menu will close.

Dialogs

The v-dialog lets us display a dialog.

To use it, we write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-row justify="center">
          <v-btn color="primary" dark @click.stop="dialog = true">Open Dialog</v-btn>

          <v-dialog v-model="dialog" max-width="290">
            <v-card>
              <v-card-title class="headline">Title</v-card-title>
              <v-card-text>Lorem ipsum.</v-card-text>
              <v-card-actions>
                <v-spacer></v-spacer>
                <v-btn color="green darken-1" text @click="dialog = false">Cancel</v-btn>
                <v-btn color="green darken-1" text @click="dialog = false">OK</v-btn>
              </v-card-actions>
            </v-card>
          </v-dialog>
        </v-row>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    dialog: false,
  }),
};
</script>

to create a dialog with the v-dialog component.

v-model binds to the dialog state to control the opening and closing of the dialog.

We also have the v-btn to set dialog to false when we click on the buttons.

The Open Dialog button sets dialog to true when we click it so the dialog opens when we click it.

Conclusion

We can make a chip show a menu when we click it.

Also, we can create a dialog box with the v-dialog component.

Categories
Vuetify

Vuetify — Chips

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Chips

We can use the v-chip component to add a chip.

It conveys a small piece of information.

The close prop lets the chip become interactive.

To add one, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" color="primary">Primary</v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

We add the v-chip component with the color prop to change the color.

Icon

We can add an icon inside the chip.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" color="indigo" text-color="white">
          <v-avatar left>
            <v-icon>mdi-account-circle</v-icon>
          </v-avatar>James
        </v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

We add a v-avatar component with a v-icon inside.

Then we’ll see the icon to the left of the text.

Outlined

The outlined prop will make the chip display with an outline.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" color="success" outlined>
          <v-icon left>mdi-server-plus</v-icon>Status
        </v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

Now we’ll see a white background with a border on the chip.

Label

We can make the chip border-radius less round to make a label.

The label prop will adjust the border-radius to be less round:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" color="pink" label text-color="white">
          <v-icon left>mdi-label</v-icon>Tags
        </v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

Sizes

We can have various sizes with the v-chip component.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" x-small>x-small</v-chip>
        <v-chip class="ma-2" small>small</v-chip>
        <v-chip class="ma-2">Default</v-chip>
        <v-chip class="ma-2" large>large</v-chip>
        <v-chip class="ma-2" x-large>x-large</v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
};
</script>

We have the x-small , small , large and x-large props to change the chip size.

Filter

The filter prop lets us show an additional icon if it’s active.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip class="ma-2" :input-value="active" filter filter-icon="mdi-minus">chip</v-chip>
        <v-switch v-model="active" label="Active"></v-switch>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    active: false,
  }),
};
</script>

We have the v-chip component with the input-value prop.

When it’s true , then we show an extra icon with the filter prop.

filter-icon lets us set the icon to show with active is true .

Conclusion

We can add chips to show small amounts of information.

The icon can be shown and toggled.

Categories
Vuetify

Vuetify — Chips and Inputs

Vuetify is a popular UI framework for Vue apps.

In this article, we’ll look at how to work with the Vuetify framework.

Closable Chips

We can create a closable chop with the v-model directive.

For example, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip
          v-if="chip"
          class="ma-2"
          close
          color="green"
          outlined
          @click:close="chip = false"
        >Success</v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    chip: true,
  }),
};
</script>

We listen to the click:close event with to set chip to false .

The v-if directive controls whether the chip is displayed.

Action Chips

We can have chips that do something when we click it.

For instance, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-chip @click="blinds">
          <v-icon left>mdi-blinds</v-icon>Close blinds
        </v-chip>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({}),
  methods: {
    blinds() {
      alert("Toggling Blinds");
    },
  },
};
</script>

We listen to the click event by setting the click handler top the blinds method.

Then we run the method when we click it.

Chips In Selects

We can use chips in a select element to display selected data.

For instance, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-combobox
          v-model="chips"
          :items="items"
          chips
          clearable
          label="Your favorite hobbies"
          multiple
          solo
        >
          <template v-slot:selection="{ attrs, item, select, selected }">
            <v-chip
              v-bind="attrs"
              :input-value="selected"
              close
              @click="select"
              @click:close="remove(item)"
            >{{ item }}</v-chip>
          </template>
        </v-combobox>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    chips: ["eat", "drink", "sleep"],
    items: ["walk", "read"],
  }),
  methods: {
    remove(item) {
      this.chips.splice(this.chips.indexOf(item), 1);
      this.chips = [...this.chips];
    },
  },
};
</script>

We listen to the click event to run the select method provided by the selection slot of the v-combobox component.

v-combobox is the dropdown component.

Also, we listen to the click:close event to remove an item when we click on the ‘x’ on the chip.

Custom Lists

We can use chips in a custom list.

To do that, we can write:

<template>
  <v-container>
    <v-row>
      <v-col col="12">
        <v-card class="mx-auto" max-width="500">
          <v-container class="py-0">
            <v-row align="center" justify="start">
              <v-col v-for="(selection, i) in selections" :key="selection.text" class="shrink">
                <v-chip :disabled="loading" close @click:close="selected.splice(i, 1)">
                  <v-icon left v-text="selection.icon"></v-icon>
                  {{ selection.text }}
                </v-chip>
              </v-col>

              <v-col v-if="!allSelected" cols="12">
                <v-text-field
                  ref="search"
                  v-model="search"
                  full-width
                  hide-details
                  label="Search"
                  single-line
                ></v-text-field>
              </v-col>
            </v-row>
          </v-container>

          <v-divider v-if="!allSelected"></v-divider>

          <v-list>
            <template v-for="item in categories">
              <v-list-item
                v-if="!selected.includes(item)"
                :key="item.text"
                :disabled="loading"
                @click="selected.push(item)"
              >
                <v-list-item-avatar>
                  <v-icon :disabled="loading" v-text="item.icon"></v-icon>
                </v-list-item-avatar>
                <v-list-item-title v-text="item.text"></v-list-item-title>
              </v-list-item>
            </template>
          </v-list>

          <v-divider></v-divider>

          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn
              :disabled="!selected.length"
              :loading="loading"
              color="purple"
              text
              @click="next"
            >Next</v-btn>
          </v-card-actions>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: "HelloWorld",
  data: () => ({
    items: [
      {
        text: "nature",
        icon: "mdi-nature",
      },
      {
        text: "wine",
        icon: "mdi-glass-wine",
      },
      {
        text: "calendar",
        icon: "mdi-calendar-range",
      },
    ],
    loading: false,
    search: "",
    selected: [],
  }),

  computed: {
    allSelected() {
      return this.selected.length === this.items.length;
    },
    categories() {
      const search = this.search.toLowerCase();

      if (!search) return this.items;

      return this.items.filter((item) => {
        const text = item.text.toLowerCase();

        return text.indexOf(search) > -1;
      });
    },
    selections() {
      const selections = [];

      for (const selection of this.selected) {
        selections.push(selection);
      }

      return selections;
    },
  },

  watch: {
    selected() {
      this.search = "";
    },
  },

  methods: {
    next() {
      this.loading = true;

      setTimeout(() => {
        this.search = "";
        this.selected = [];
        this.loading = false;
      }, 2000);
    },
  },
};
</script>

We put the v-chip component within the v-col to lay them out when we select items from the v-text-field .

The v-text-field lets us enter some text and the v-list below it will show the items that match what we type.

The categories is a computed property to return the matches.

Conclusion

We can add chips to do different things.

They can also be in dropdowns.