Return to Homepage

[Draft] V-Card In Depth

Framework Breakdown:

Diving into the innards of Vuetify

Introduction

As someone who loves Vuetify and formally a contributor. I wanted to dive back in and see all the amazing changes the made in this newest version over the past years. My first thought was to dive into one of my long time favorite and most used component V-Card.

Overview

Diving into the Vuetify Component Library can be overwhelming. I decided to break down the V-Card component into a 4 areas I wanted to explore.

  1. How does it get exported for use?
  2. How is the component created?
  3. How am I able to use the props/attributes availiable in this component?
  4. How is it possible to declare this component in 3 different ways?

How does it get exported for use?

When we install Vuetify into our application we are able to import the V-Card like this:

import { VCard } from 'vueitfy';

A line many of us are familiar with. How does this work and where do all of the exports for other components? The flow of exporting the card component is as follows:

Once the component is exported to the index.ts of the /components folder. Vuetify runs a build script (yarn build) to package it. This is where the magic happens. The build script uses rollup to bundle the component and other parts of vuetify into a single folder for distribution. This dist folder is what we use/refrence when we import Vuetify into our application.

(Results of yarn build)

This is how Vuetify we go from a component being defined in the Vuetify codebase to being packages and exposed to us for use in our application.

How Is It Created?

Diving into the codebase, I found the V-Card component in: vuetify>packages>vuetify>src>components>VCardVuetify V-Card Directory Image

The first thing I noticed was the VCard.tsx file. This is the main file orchestrating the composition and use of other components within the same directory. Inside the VCard.tsx file we see the various components being imported and used throughout the file.

// Components
import { VCardActions } from './VCardActions'
import { VCardItem } from './VCardItem'
import { VCardText } from './VCardText'
import { VDefaultsProvider } from '@/components/VDefaultsProvider'
import { VImg } from '@/components/VImg'

If we jump to line 50 & 51 we'll see exactly where VCard is defined as a component and exported for use.

export const VCard = genericComponent<VCardSlots>()({
  name: 'VCard',
  // more code....
})

Why use this instad of the standard defineComponent as typically used in Vue applicaitons? example below:

export const VCard = defineComponent({
  name: 'VCard',
  // more code....
})

TLDR: genericComponent essentially for the use of generic props and slots when defining components. view here for more details.

Jumping to line 110 we are able to see exactly where the VCard componnet is initiating rendering and line 121 is where we start builing the components template.

line 110

useRender(() => {
// more code.....
})

useRender is a custom rendering function that essentially does the following:

  • Gets the current instance of the Node
    • Checks if it's called inside a "setup" function
    • If it is, it returns the view model
  • It takes the valid view model and uses 'vue 3' .render function to return the valid vue model as a Virtual DOM tree to be added to our applications VDOM Tree.

line 121

return (
// building our component....
)

Parts of the Component.

The component can be broken down into several parts:

  • Shell: Where we see the <Tag></Tag> component encapsulating the innards of V-Card
  • Layout: The parts of the components that render conditially based upon the variables with the prefix "has" and slots (ex. hasImage, hasText, slots.action, slots.image, ect.)
  • Props/Options: The attributes/props section is where the default options are declared to interact/modify the V-Card Component. ex.(onClick, title, subtitle, actions, ect.)
  • Classes: Where the component inherits both V-Card specific CSS classes and globally configured classes.

Shell

Inside the return statement on line 122 we see <Tag>. What exactly is this "Tag" component? The component is essentially an agnostic component that inherits the name of the defined component's name property. (Fact check. Looks likes it's a div by default.)

Layout

Inside the shell the layout is defined. There are a multitude of ternary statements determining what to render. An example of this is on line 151:

{ hasImage && (
    <VDefaultsProvider
      key="image"
      defaults={{
        VImg: {
          cover: true,
          src: props.image,
        },
      }}
    >
      <div class="v-card__image">
        { slots.image?.() ?? <VImg /> }
      </div>
    </VDefaultsProvider>
  ) 
}

This statement is determining if there's an image and if there is the <V-Img /> tag is rendered inside the div with v-card__image styling.

to be continued.........