Skip to content

Layouts & Theming in Vuetify 3

Introduction

Do you want to avoid tinkering with CSS to get your website looking just right?

Branding is everything in today's digital landscape. With Vuetify 3's customizable theming options, you can create web projects that perfectly reflect your unique branding, and visual identity. Additionally, you can reduce the duplicated code by creating layouts representing your application's different page structures.

In a previous article introducing Vuetify 3 with Vue 3, we created an application that allowed us to add, display, and delete jokes. image If you'd like to follow along with this article, please clone the GitHub repository.

git clone https://github.com/thisdot/blog-demos.git
# or `git@github.com:thisdot/blog-demos.git` for ssh

# then cd into the project directory
cd layouts-and-theming-in-vueityf

In this article, we'll go over how you can create layouts in Vuetify 3 to allow you to reuse the same layout for pages that share the same structure. We will also go over how you can customize the look and feel of your application to match your brand's visual identity through the powerful theming tools that Vuetify 3 offers us.

Layouts in Vuetify 3

What are layouts, and how are they useful?

In web development, layouts are akin to blueprints for the structure of your web pages. They provide a consistent and reusable frame for the different pages of an application. A well-designed layout can improve the user experience by providing familiarity and predictability as the user navigates through other parts of your application.

Layouts are particularly helpful in reducing code duplication. Instead of defining the same structure for each page—headers, footers, and navigation menus, you define them once in a layout, and then apply that layout to any page that uses the same structure. This speeds up development, and makes your code easier to maintain.

Using Layouts in Vuetify 3

Creating a layout in Vuetify 3 is as simple as creating a new Vue component. This component will include the common elements shared across multiple pages like headers, footers, and navigation bars. Here is an example of a basic layout:

<template>
  <v-app>
    <v-main>
      <v-header> ... </v-header>
      <v-navigation-drawer> ... </v-navigation-drawer>
      <router-view/>
    </v-main>
    <v-footer> ... </v-footer>
  </v-app>
</template>

This layout has a header, a navigation drawer, and a footer. The <router-view/> component is where the content of the specific pages will be injected.

Building a layout for our application

Let's create a layout for our application. We'll have a top navigation bar and a footer. Inside the layouts directory, create a new file named Default.vue and add the following code:

<template>
  <v-app>
    <v-app-bar app color="primary" dark>
      <v-toolbar-title>Joke Machine</v-toolbar-title>
    </v-app-bar>

    <v-main>
      <router-view/>
    </v-main>

    <v-footer color="primary" app>
      <span>&copy; 2023 Joke Machine</span>
    </v-footer>
  </v-app>
</template>

Additionally, in order for us to use our layout, we will need to modify our router/index.ts file to use the Default.vue component:

const routes = [
{
    //...
    component: () => import('@/layouts/Default.vue'),
    //...
}

This will make sure that our respective pages use the Default.vue layout that we created. The contents of the pages will appear in place of <router-view> in the layout.

It is also worth noting that you can create, and nest as many layouts as you want.

Theming in Vuetify 3

Themes allow you to customize your application's default colors, surfaces, and more. If your brand has specific colors and styling, you can theme your Vuetify application to resemble your brand through theming better. Additionally, Vuetify 3 allows you to modify your theme in real-time programmatically. [Vuetify 3] also comes with light and dark themes pre-installed.

Theming API

Vuetify 3 offers us 2 main APIs for working with themes:

  • useTheme is a composable that allows us to get information about the current theme and will enable us to modify the existing theme.
  • v-theme-provider is used in the <template> section of your Vue files to modify the theme of all of its children.

Updating the theme of our application

Updating the theme of our application is straightforward with Vuetify 3. Let's customize our application's primary and secondary colors. In the vuetify.ts file, modify the themes section to contain the following styles:

import { createVuetify } from 'vuetify'
import 'vuetify/styles'

const vuetify = createVuetify({
  theme: {
    themes: {
      light: {
        background: '#FFFFFF',
        surface: '#F2F5F8',
        primary: '#6200EE',
        secondary: '#03DAC6',
        error: '#B00020',
        info: '#2196F3',
        success: '#4CAF50',
        warning: '#FB8C00',
      },
    },
  },
})

In this example, we're defining a custom 'light' theme. If you want to use a dark theme, or any other named theme, you can add those as additional properties within the themes object. For example:

themes: {
  light: { /* ... */ },
  dark: { /* ... */ },
}

And... That's it! By changing the various config options in the vuetify.ts file, you can modify how your application looks and feels to match your brand. If you'd like to learn more about themes and all the options you can provide, please check out the official Vuetify documentation.

Conclusion

In this article, we've gone through the concepts of layouts and theming in Vuetify 3. We've seen how layouts can reduce code duplication, and provide consistency across your application. We've looked at how Vuetify's theming features allow you to customize your application to match your brand's visual identity.

Understanding and utilizing these features effectively can significantly enhance the development experience and the end user's interaction with your application. Remember, a well-structured and visually appealing application not only attracts users, but also retains them. Happy coding!

This Dot Labs is a development consultancy that is trusted by top industry companies, including Stripe, Xero, Wikimedia, Docusign, and Twilio. This Dot takes a hands-on approach by providing tailored development strategies to help you approach your most pressing challenges with clarity and confidence. Whether it's bridging the gap between business and technology or modernizing legacy systems, you’ll find a breadth of experience and knowledge you need. Check out how This Dot Labs can empower your tech journey.

You might also like

Nuxt DevTools v1.0: Redefining the Developer Experience Beyond Conventional Tools cover image

Nuxt DevTools v1.0: Redefining the Developer Experience Beyond Conventional Tools

In the ever-evolving world of web development, Nuxt.js has taken a monumental leap with the launch of Nuxt DevTools v1.0. More than just a set of tools, it's a game-changer—a faithful companion for developers. This groundbreaking release, available for all Nuxt projects and being defaulted from Nuxt v3.8 onwards, marks the beginning of a new era in developer tools. It's designed to simplify our development journey, offering unparalleled transparency, performance, and ease of use. Join me as we explore how Nuxt DevTools v1.0 is set to revolutionize our workflow, making development faster and more efficient than ever. What makes Nuxt DevTools so unique? Alright, let's start delving into the features that make this tool so amazing and unique. There are a lot, so buckle up! In-App DevTools The first thing that caught my attention is that breaking away from traditional browser extensions, Nuxt DevTools v1.0 is seamlessly integrated within your Nuxt app. This ensures universal compatibility across browsers and devices, offering a more stable and consistent development experience. This setup also means the tools are readily available in the app, making your work more efficient. It's a smart move from the usual browser extensions, making it a notable highlight. To use it you just need to press Shift + Option + D` (macOS) or `Shift + Alt + D` (Windows): With simple keystrokes, the Nuxt DevTools v1.0 springs to life directly within your app, ready for action. This integration eliminates the need to toggle between windows or panels, keeping your workflow streamlined and focused. The tools are not only easily accessible but also intelligently designed to enhance your productivity. Pages, Components, and Componsables View The Pages, Components, and Composables View in Nuxt DevTools v1.0 are a clear roadmap for your app. They help you understand how your app is built by simply showing its structure. It's like having a map that makes sense of your app's layout, making the complex parts of your code easier to understand. This is really helpful for new developers learning about the app and experienced developers working on big projects. Pages View lists all your app's pages, making it easier to move around and see how your site is structured. What's impressive is the live update capability. As you explore the DevTools, you can see the changes happening in real-time, giving you instant feedback on your app's behavior. Components View is like a detailed map of all the parts (components) your app uses, showing you how they connect and depend on each other. This helps you keep everything organized, especially in big projects. You can inspect components, change layouts, see their references, and filter them. By showcasing all the auto-imported composables, Nuxt DevTools provides a clear overview of the composables in use, including their source files. This feature brings much-needed clarity to managing composables within large projects. You can also see short descriptions and documentation links in some of them. Together, these features give you a clear picture of your app's layout and workings, simplifying navigation and management. Modules and Static Assets Management This aspect of the DevTools revolutionizes module management. It displays all registered modules, documentation, and repository links, making it easy to discover and install new modules from the community! This makes managing and expanding your app's capabilities more straightforward than ever. On the other hand, handling static assets like images and videos becomes a breeze. The tool allows you to preview and integrate these assets effortlessly within the DevTools environment. These features significantly enhance the ease and efficiency of managing your app's dynamic and static elements. The Runtime Config and Payload Editor The Runtime Config and Payload Editor in Nuxt DevTools make working with your app's settings and data straightforward. The Runtime Config lets you play with different configuration settings in real time, like adjusting settings on the fly and seeing the effects immediately. This is great for fine-tuning your app without guesswork. The Payload Editor is all about managing the data your app handles, especially data passed from server to client. It's like having a direct view and control over the data your app uses and displays. This tool is handy for seeing how changes in data impact your app, making it easier to understand and debug data-related issues. Open Graph Preview The Open Graph Preview in Nuxt DevTools is a feature I find incredibly handy and a real time-saver. It lets you see how your app will appear when shared on social media platforms. This tool is crucial for SEO and social media presence, as it previews the Open Graph tags (like images and descriptions) used when your app is shared. No more deploying first to check if everything looks right – you can now tweak and get instant feedback within the DevTools. This feature not only streamlines the process of optimizing for social media but also ensures your app makes the best possible first impression online. Timeline The Timeline feature in Nuxt DevTools is another standout tool. It lets you track when and how each part of your app (like composables) is called. This is different from typical performance tools because it focuses on the high-level aspects of your app, like navigation events and composable calls, giving you a more practical view of your app's operation. It's particularly useful for understanding the sequence and impact of events and actions in your app, making it easier to spot issues and optimize performance. This timeline view brings a new level of clarity to monitoring your app's behavior in real-time. Production Build Analyzer The Production Build Analyzer feature in Nuxt DevTools v1.0 is like a health check for your app. It looks at your app's final build and shows you how to make it better and faster. Think of it as a doctor for your app, pointing out areas that need improvement and helping you optimize performance. API Playground The API Playground in Nuxt DevTools v1.0 is like a sandbox where you can play and experiment with your app's APIs. It's a space where you can easily test and try out different things without affecting your main app. This makes it a great tool for trying out new ideas or checking how changes might work. Some other cool features Another amazing aspect of Nuxt DevTools is the embedded full-featured VS Code. It's like having your favorite code editor inside the DevTools, with all its powerful features and extensions. It's incredibly convenient for making quick edits or tweaks to your code. Then there's the Component Inspector. Think of it as your code's detective tool. It lets you easily pinpoint and understand which parts of your code are behind specific elements on your page. This makes identifying and editing components a breeze. And remember customization! Nuxt DevTools lets you tweak its UI to suit your style. This means you can set up the tools just how you like them, making your development environment more comfortable and tailored to your preferences. Conclusion In summary, Nuxt DevTools v1.0 marks a revolutionary step in web development, offering a comprehensive suite of features that elevate the entire development process. Features like live updates, easy navigation, and a user-friendly interface enrich the development experience. Each tool within Nuxt DevTools v1.0 is thoughtfully designed to simplify and enhance how developers build and manage their applications. In essence, Nuxt DevTools v1.0 is more than just a toolkit; it's a transformative companion for developers seeking to build high-quality web applications more efficiently and effectively. It represents the future of web development tools, setting new standards in developer experience and productivity....

Understanding Vue's Reactive Data cover image

Understanding Vue's Reactive Data

Introduction Web development has always been about creating dynamic experiences. One of the biggest challenges developers face is managing how data changes over time and reflecting these changes in the UI promptly and accurately. This is where Vue.js, one of the most popular JavaScript frameworks, excels with its powerful reactive data system. In this article, we dig into the heart of Vue's reactivity system. We unravel how it perfectly syncs your application UI with the underlying data state, allowing for a seamless user experience. Whether new to Vue or looking to deepen your understanding, this guide will provide a clear and concise overview of Vue's reactivity, empowering you to build more efficient and responsive Vue 3 applications. So, let’s kick off and embark on this journey to decode Vue's reactive data system. What is Vue's Reactive Data? What does it mean for data to be ”'reactive”? In essence, when data is reactive, it means that every time the data changes, all parts of the UI that rely on this data automatically update to reflect these changes. This ensures that the user is always looking at the most current state of the application. At its core, Vue's Reactive Data is like a superpower for your application data. Think of it like a mirror - whatever changes you make in your data, the user interface (UI) reflects these changes instantly, like a mirror reflecting your image. This automatic update feature is what we refer to as “reactivity”. To visualize this concept, let's use an example of a simple Vue application displaying a message on the screen: `javascript import { createApp, reactive } from 'vue'; const app = createApp({ setup() { const state = reactive({ message: 'Hello Vue!' }); return { state }; } }); app.mount('#app'); ` In this application, 'message' is a piece of data that says 'Hello Vue!'. Let's say you change this message to 'Goodbye Vue!' later in your code, like when a button is clicked. `javascript state.message = 'Goodbye Vue!'; ` With Vue's reactivity, when you change your data, the UI automatically updates to 'Goodbye Vue!' instead of 'Hello Vue!'. You don't have to write extra code to make this update happen - Vue's Reactive Data system takes care of it. How does it work? Let's keep the mirror example going. Vue's Reactive Data is the mirror that reflects your data changes in the UI. But how does this mirror know when and what to reflect? That's where Vue's underlying mechanism comes into play. Vue has a behind-the-scenes mechanism that helps it stay alerted to any changes in your data. When you create a reactive data object, Vue doesn't just leave it as it is. Instead, it sends this data object through a transformation process and wraps it up in a Proxy. Proxy objects are powerful and can detect when a property is changed, updated, or deleted. Let's use our previous example: `javascript import { createApp, reactive } from 'vue'; const app = createApp({ setup() { const state = reactive({ message: 'Hello Vue!' }); return { state }; } }); app.mount('#app'); ` Consider our “message” data as a book in a library. Vue places this book (our data) within a special book cover (the Proxy). This book cover is unique - it's embedded with a tracking device that notifies Vue every time someone reads the book (accesses the data) or annotates a page (changes the data). In our example, the reactive function creates a Proxy object that wraps around our state object. When you change the 'message': `javascript state.message = 'Goodbye Vue!'; ` The Proxy notices this (like a built-in alarm going off) and alerts Vue that something has changed. Vue then updates the UI to reflect this change. Let’s look deeper into what Vue is doing for us and how it transforms our object into a Proxy object. You don't have to worry about creating or managing the Proxy; Vue handles everything. `javascript const state = reactive({ message: 'Hello Vue!' }); // What vue is doing behind the scenes: function reactive(obj) { return new Proxy(obj, { // target = state and key = message get(target, key) { track(target, key) return target[key] }, set(target, key, value) { target[key] = value // Here Vue will trigger its reactivity system to update the DOM. trigger(target, key) } }) } ` In the example above, we encapsulate our object, in this case, “state”, converting it into a Proxy object. Note that within the second argument of the Proxy, we have two methods: a getter and a setter. The getter method is straightforward: it merely returns the value, which in this instance is “state.message” equating to 'Hello Vue!' Meanwhile, the setter method comes into play when a new value is assigned, as in the case of “state.message = ‘Hey young padawan!’”. Here, “value” becomes our new 'Hey young padawan!', prompting the property to update. This action, in turn, triggers the reactivity system, which subsequently updates the DOM. Venturing Further into the Depths If you have been paying attention to our examples above, you might have noticed that inside the Proxy` method, we call the functions `track` and `trigger` to run our reactivity. Let’s try to understand a bit more about them. You see, Vue 3 reactivity data is more about Proxy objects. Let’s create a new example: `vue import { reactive, watch, computed, effect } from "vue"; const state = reactive({ showSword: false, message: "Hey young padawn!", }); function changeMessage() { state.message = "It's dangerous to go alone! Take this."; } effect(() => { if (state.message === "It's dangerous to go alone! Take this.") { state.showSword = true; } }); {{ state.message }} Click! ` In this example, when you click on the button, the message's value changes. This change triggers the effect function to run, as it's actively listening for any changes in its dependencies__. How does the effect` property know when to be called? Vue 3 has three main functions to run our reactivity: effect`, `track`, and `trigger`. The effect` function is like our supervisor. It steps in and takes action when our data changes – similar to our effect method, we will dive in more later. Next, we have the track` function. It notes down all the important data we need to keep an eye on. In our case, this data would be `state.message`. Lastly, we've got the trigger` function. This one is like our alarm bell. It alerts the `effect` function whenever our important data (the stuff `track` is keeping an eye on) changes. In this way, trigger`, `track`, and `effect` work together to keep our Vue application reacting smoothly to changes in data. Let’s go back to them: `javascript function reactive(obj) { return new Proxy(obj, { get(target, key) { // target = state & key = message track(target, key) // keep an eye for this return target[key] }, set(target, key, value) { target[key] = value trigger(target, key) // trigger the effects! } }) } ` Tracking (Dependency Collection) Tracking is the process of registering dependencies between reactive objects and the effects that depend on them. When a reactive property is read, it's "tracked" as a dependency of the current running effect. When we execute track()`, we essentially store our effects in a Set object. But what exactly is an "effect"? If we revisit our previous example, we see that the effect method must be run whenever any property changes. This action — running the effect method in response to property changes — is what we refer to as an "Effect"! (computed property, watcher, etc.) > Note: We'll outline a basic, high-level overview of what might happen under the hood. Please note that the actual implementation is more complex and optimized, but this should give you an idea of how it works. Let’s see how it works! In our example, we have the following reactive object: `javascript const state = reactive({ showSword: false, message: "Hey young padawn!", }); // which is transformed under the hood to: function reactive(obj) { return new Proxy(obj, { get(target, key) { // target = state | key = message track(target, key) // keep an eye for this return target[key] }, set(target, key, value) { target[key] = value trigger(target, key) // trigger the effects! } }) } ` We need a way to reference the reactive object with its effects. For that, we use a WeakMap. Which type is going to look something like this: `typescript WeakMap>> ` We are using a WeakMap to set our object state as the target (or key). In the Vue code, they call this object `targetMap`. Within this targetMap` object, our value is an object named `depMap` of Map type. Here, the keys represent our properties (in our case, that would be `message` and `showSword`), and the values correspond to their effects – remember, they are stored in a Set that in Vue 3 we refer to as `dep`. Huh… It might seem a bit complex, right? Let's make it more straightforward with a visual example: With the above explained, let’s see what this Track` method kind of looks like and how it uses this `targetMap`. This method essentially is doing something like this: `javascript let activeEffect; // we will see more of this later function track(target, key) { if (activeEffect) { // depsMap` maps targets to their keys and dependent effects let depsMap = targetMap.get(target); // If we don't have a depsMap for this target in our targetMap`, create one. if (!depsMap) { depsMap = new Map(); targetMap.set(target, depsMap); } let dep = depsMap.get(key); if (!dep) { // If we don't have a set of effects for this key in our depsMap`, create one. dep = new Set(); depsMap.set(key, dep); } // Add the current effect as a dependency dep.add(activeEffect); } } ` At this point, you have to be wondering, how does Vue 3 know what activeEffect` should run? Vue 3 keeps track of the currently running effect by using a global variable. When an effect is executed, Vue temporarily stores a reference to it in this global variable, allowing the track` function to access the currently running effect and associate it with the accessed reactive property. This global variable is called inside Vue as `activeEffect`. Vue 3 knows which effect is assigned to this global variable by wrapping the effects functions in a method that invokes the effect whenever a dependency changes. And yes, you guessed, that method is our effect` method. `javascript effect(() => { if (state.message === "It's dangerous to go alone! Take this.") { state.showSword = true; } }); ` This method behind the scenes is doing something similar to this: `javascript function effect(update) { //the function we are passing in const effectMethod = () => { // Assign the effect as our activeEffect` activeEffect = effectMethod // Runs the actual method, also triggering the get` trap inside our proxy update(); // Clean the activeEffect after our Effect has finished activeEffect = null } effectMethod() } ` The handling of activeEffect` within Vue's reactivity system is a dance of careful timing, scoping, and context preservation. Let’s go step by step on how this is working all together. When we run our `Effect` method for the first time, we call the `get` trap of the Proxy. `javascript function effect(update) const effectMethod = () => { // Storing our active effect activeEffect = effectMethod // Running the effect update() ... } ... } effect(() => { // we call the the get` trap when getting our `state.message` if (state.message === "It's dangerous to go alone! Take this.") { state.showSword = true; } }); ` When running the get` trap, we have our `activeEffect` so we can store it as a dependency. `javascript function reactive(obj) { return new Proxy(obj, { // Gets called when our effect runs get(target, key) { track(target, key) // Saves the effect return target[key] }, // ... (other handlers) }) } function track(target, key) { if (activeEffect) { //... rest of the code // Add the current effect as a dependency dep.add(activeEffect); } } ` This coordination ensures that when a reactive property is accessed within an effect, the track function knows which effect is responsible for that access. Trigger Method Our last method makes this Reactive system to be complete. The trigger` method looks up the dependencies for the given target and key and re-runs all dependent effects. `javascript function trigger(target, key) { const depsMap = targetMap.get(target); if (!depsMap) return; // no dependencies, no effects, no need to do anything const dep = depsMap.get(key); if (!dep) return; // no dependencies for this key, no need to do anything // all dependent effects to be re-run dep.forEach(effect => { effect() }); } ` Conclusion Diving into Vue 3's reactivity system has been like unlocking a hidden superpower in my web development toolkit, and honestly, I've had a blast learning about it. From the rudimentary elements of reactive data and instantaneous UI updates to the intricate details involving Proxies, track and trigger functions, and effects, Vue 3's reactivity is an impressively robust framework for building dynamic and responsive applications. In our journey through Vue 3's reactivity, we've uncovered how this framework ensures real-time and precise updates to the UI. We've delved into the use of Proxies to intercept and monitor variable changes and dissected the roles of track and trigger functions, along with the 'effect' method, in facilitating seamless UI updates. Along the way, we've also discovered how Vue ingeniously manages data dependencies through sophisticated data structures like WeakMaps and Sets, offering us a glimpse into its efficient approach to change detection and UI rendering. Whether you're just starting with Vue 3 or an experienced developer looking to level up, understanding this reactivity system is a game-changer. It doesn't just streamline the development process; it enables you to create more interactive, scalable, and maintainable applications. I love Vue 3, and mastering its reactivity system has been enlightening and fun. Thanks for reading, and as always, happy coding!...

Getting Started with Vuetify in Vue 3 cover image

Getting Started with Vuetify in Vue 3

If you're here to learn about Vuetify and how to use it with Vue 3, you've come to the right place. In this article, we'll introduce Vuetify, a Material Design component framework for Vue.js, and walk you through setting it up in a Vue 3 project. We will also build a simple web app that allows us to create and vue jokes. Oh, sorry, view jokes! What is Vuetify? Vuetify is a VueJS Material Design component framework. That is to say that Vuetify provides us with prebuilt components and features (e.g. internationalization, tree shaking, theming, etc.) to help us build Vue applications faster. Additionally, Vuetify components have built-in standard functionality, such as validation in form inputs, or various disabled states in buttons. You can check out a full list of components supported by Vuetify on their official documentation website. Setting things up Before we get started, you will need the following on your machine: - NodeJS installed - A NodeJS package manager e.g. yarn or npm installed - Intermediate knowledge of Vue 3.x with the composition API If you’d like to follow along, feel free to clone the github repository for this article. `shell git clone https://github.com/thisdot/blog-demos.git or `git@github.com:thisdot/blog-demos.git` for ssh then cd into the project directory cd getting-started-with-vuetify ` Installing Vuetify We will be using yarn` to install and setup Vuetify 3 (the version that supports Vue 3) in this case. First, let's create a new Vuetify project. You can do this by running the following command in your terminal or command prompt: `shell yarn create vuetify ` This will create a new Vuetify project. For our jokes app, we will use the Essentials (Vuetify, VueRouter, Pinia)` preset when creating our app. We will also be using TypeScript for our app, but this is not necessary. Since VueJS allows us to build incrementally, if you would like to instead add Vuetify to an existing project, you can use the manual steps provided by the Vuetify team. Testing our application Once we have installed and configured our application, cd` into the project's directly, and run the app using the following command: `shell yarn dev #or npm run dev` (if using npm instead) ` Visit localhost:3000/` to see your app in action. Vuetify project folder structure Our Vuetify project is generally structured as follows: - public` - Contains static assets that do not need preprocessing eg. our application `favicon` - src` - Contains our VueJS source code. We'll mostly be working here. - assets` - Assets that need to be preprocessed eg. our images that may need to be compressed when building for production - components` - layouts` - Layouts - plugins` - Everything gets wired up here (registration of our app as well as vuetify, our router & pinia) - router` - Vue router-related functionality - store` - Pinia store - styles` - views` - our web app's "pages" Worth noting before building It is worth noting that all components in Vuetify start with a v-` for example: - v-form` is a form - v-btn` is a button component - v-text-field` is an input field and so on and so forth. When creating your own components, it is recommended to use a different naming approach so that it is easier to know which components are Vuetify components, and which ones are your components. Building our Vuetify application We will build a web app that allows us to add, view and delete jokes. Here are the steps we will take to build our app: - Delete unnecessary boilerplate from generated Vuetify app - Add a joke` pinia store - we'll be using this to store our jokes globally using Pinia - Create our joke components - components/jokes/CreateJokeForm.vue` - the form that allows us to add jokes - components/jokes/JokeList.vue` - Lists our jokes out. - Add our components to our Home.vue` to view them in our home page Setting up the jokes pinia store In the src/store/` directory, create a new file called `joke.ts` that will serve as our Pinia store for storing our jokes. The file content for this will be as follows: `ts import { defineStore } from "pinia"; export interface Joke { id: number; title: string; punchline: string; } export const useJokeStore = defineStore({ id: "joke", state: () => ({ jokes: [] as Joke[], }), actions: { addJoke(joke: Joke) { this.jokes.push(joke); }, removeJoke(id: number) { this.jokes = this.jokes.filter((joke) => joke.id !== id); }, }, }); ` This code defines a special storage space called a "store" for jokes in our Vue.js app. This store keeps track of all the jokes we've added through our app's form. Each joke has an ID, title, and punchline. The addJoke` function in the store is used to add a new joke to the store when a user submits the form. The `removeJoke` function is used to delete a joke from the store when a user clicks the delete button. By using this store, we can keep track of all the jokes that have been added through the app, and we can easily add or remove jokes without having to manage the list ourselves. Creating the joke components CreateJokeForm.vue Create a file in src/components/jokes/` called `CreateJokeForm.vue`. This file defines a Vue.js component that displays a form for adding new jokes. The file should have the following contents: Template section `html Submit Joke ` In the template section, we define a form using the v-form component from Vuetify. We bind the form's submit event to the submitJoke method, which will be called when the form is submitted. Inside the form, we have two text fields" one for the joke title, and one for the punchline. These text fields are implemented using the v-text-field component from Vuetify. The label prop sets the label for each text field, and the outlined prop creates an outlined style for each text field. The required prop sets the fields as required, meaning that they must be filled in before the form can be submitted. Finally, we have a submit button implemented using the v-btn component from Vuetify. The button is disabled until both the title and punchline fields are filled in, which is accomplished using the :disabled prop with a computed property that checks if both fields are empty. Script section `ts import { computed, ref } from "vue"; import { Joke, useJokeStore } from "@/store/joke"; const jokeStore = useJokeStore(); const jokeTitle = ref(""); const jokePunchline = ref(""); const joke = computed(() => ({ id: jokeStore.jokes.length + 1, title: jokeTitle.value, punchline: jokePunchline.value, })); function submitJoke() { jokeStore.addJoke(joke.value); jokeTitle.value = ""; jokePunchline.value = ""; } ` In the script section, we import some functions and types from Vue.js and the joke` store. We then define a `jokeStore` variable that holds the instance of the `useJokeStore` function from the `joke` store. We also define two ref`s, `jokeTitle`, and `jokePunchline`, which hold the values of the form's title and punchline fields, respectively. We then define a computed property, joke`, which creates a new `Joke` object using the `jokeTitle` and `jokePunchline` refs, as well as the length of the `jokes` array in the `jokeStore` to set the `id` property. Finally, we define a submitJoke` function that calls the `addJoke` method from the `jokeStore` to add the new `joke` object to the store. We also reset the `jokeTitle` and `jokePunchline` refs to empty strings. JokeList.vue Template section This one looks bulky. But in essence, all we are doing is displaying a list of jokes when they are found, and a message that lets us know that there are no jokes if we have none that have been added. `html My Jokes {{ joke.title }} {{ joke.punchline }} mdi-delete You have no jokes. Add some! ` In the template section, we define a v-card` component, which is a container component used to group related content in Vuetify. The card contains a title, which includes an excited emoticon icon from the `mdi-emoticon-excited-outline` icon set from Material Design Icons, displayed using the `v-icon` component. The jokes are displayed in a v-list`, which is a component used to display lists in Vuetify. Each joke is represented by a `v-list-item` containing a title and subtitle. The `v-row` and `v-col` components from Vuetify are used to divide each list item into two columns: one column for the joke title and punchline, and another column for the delete button. The delete button is implemented using the v-btn` component from Vuetify. The button is red, and outlined using the `color="error"` and `variant="outlined"` props, respectively. The `@click` event is used to call the `deleteJoke` function when the button is clicked. If there are no jokes in the jokeStore`, the component displays an `v-alert` component with a message to add some jokes. Script section `ts import { Joke, useJokeStore } from "@/store/joke"; const jokeStore = useJokeStore(); function deleteJoke(joke: Joke) { jokeStore.removeJoke(joke.id); } ` In the script section, we import some functions and types from the joke` store. We then define a `jokeStore` variable that holds the instance of the `useJokeStore` function from the `joke` store. We also define a deleteJoke` function that takes a `joke` object as an argument and calls the `removeJoke` method from the `jokeStore` to remove the joke from the store. This component is called JokeList.vue` and displays a list of jokes using Vuetify components like `v-card`, `v-list`, `v-list-item`, `v-row`, `v-col`, and `v-btn`. The component includes a `deleteJoke` function to remove a joke from the `jokeStore` as well. Wiring it up To display our form as well as list of jokes, we will go to the src/views/Home.vue` file and change its contents to the following: `html import CreateJokeForm from "@/components/jokes/CreateJokeForm.vue"; import JokeList from "@/components/jokes/JokeList.vue"; ` The Home.vue` file defines a Vue.js view that displays the home page of our app. The view contains a `v-container` component, which is a layout component used to provide a responsive grid system for our app. Inside the v-container`, we have a `v-row` component, which is used to create a horizontal row of content. The `v-row` contains two `v-col` components, each representing a column of content. The `cols` prop specifies that each column should take up 12 columns on small screens (i.e. the entire row width), while on medium screens, each column should take up 6 columns (i.e. half the row width). The first v-col` contains the `CreateJokeForm` component, which displays a form for adding new jokes. The second `v-col` contains the `JokeList` component, which is used to display a list of jokes that have been added through the form. In the script` section of the file, we import the `CreateJokeForm` and `JokeList` components, and register them as components for use in the template. This view provides a simple and responsive layout for our app's home page, with the CreateJokeForm` and `JokeList` components displayed side by side on medium screens and stacked on small screens. Bonus: Layouts & Theming Layouts Even though we had no need to adjust our layouts in our current jokes application, layouts are an important concept in Vuetify. They allow us to pre-define reusable layouts for our applications. These could include having a different layout for when users are logged in, and when they are logged out or layouts for different types of users. In our application, we used the default Layout (src/layouts/default/Default.vue`) but Vuetify offers us the flexibility to build different layouts for the different domains in our applications. Vuetify also supports nested layouts. You can learn more about layouts in Vuetify in the official Vuetify documentation. Theming If you have specific brand needs for your application. Vuetify has a built-in theming system that allows you to customize the look and feel of your application. You can learn more about theming in the official Vuetify theming documentation. Conclusion In this article, we introduced Vuetify, and covered how to set it up with Vue 3. We built a VueJS app that allows us to add and manage jokes. We also discussed how to use various Vuetify components to compose our UI, from v-form` for declaring forms to `v-row` for creating a row/column layout, and `v-list` for displaying a list of items among others. With this knowledge, you can start using Vuetify in your Vue 3 projects and create stunning user interfaces. Also, if you'd like to start your own VueJS project but need help with how to structure it or would like to skip the tedious setup steps of setting up a VueJS project, you can use the Vue 3 Starter.dev kit to skip the boilerplate and start building! Next steps for learning Vuetify and Vue 3 development Now that you have an understanding of Vuetify, it's time to dive deeper into its features, and explore more advanced use cases. To continue your learning journey, consider the following resources: 1. Official Vuetify documentation: The Vuetify documentation is an excellent resource for learning about all the features and components Vuetify offers. 2. Vue 3 documentation: To get the most out of Vuetify, it's essential to have a solid understanding of Vue 3. Read the official Vue 3 documentation and practice building Vue applications. Happy coding, and have fun exploring the world of Vuetify and Vue 3!...

Being a CTO at Any Level: A Discussion with Kathy Keating, Co-Founder of CTO Levels cover image

Being a CTO at Any Level: A Discussion with Kathy Keating, Co-Founder of CTO Levels

In this episode of the engineering leadership series, Kathy Keating, co-founder of CTO Levels and CTO Advisor, shares her insights on the role of a CTO and the challenges they face. She begins by discussing her own journey as a technologist and her experience in technology leadership roles, including founding companies and having a recent exit. According to Kathy, the primary responsibility of a CTO is to deliver the technology that aligns with the company's business needs. However, she highlights a concerning statistic that 50% of CTOs have a tenure of less than two years, often due to a lack of understanding and mismatched expectations. She emphasizes the importance of building trust quickly in order to succeed in this role. One of the main challenges CTOs face is transitioning from being a technologist to a leader. Kathy stresses the significance of developing effective communication habits to bridge this gap. She suggests that CTOs create a playbook of best practices to enhance their communication skills and join communities of other CTOs to learn from their experiences. Matching the right CTO to the stage of a company is another crucial aspect discussed in the episode. Kathy explains that different stages of a company require different types of CTOs, and it is essential to find the right fit. To navigate these challenges, Kathy advises CTOs to build a support system of advisors and coaches who can provide guidance and help them overcome obstacles. Additionally, she encourages CTOs to be aware of their own preferences and strengths, as self-awareness can greatly contribute to their success. In conclusion, this podcast episode sheds light on the technical aspects of being a CTO and the challenges they face. Kathy Keating's insights provide valuable guidance for CTOs to build trust, develop effective communication habits, match their skills to the company's stage, and create a support system for their professional growth. By understanding these key technical aspects, CTOs can enhance their leadership skills and contribute to the success of their organizations....