Search code examples
javascriptvue.jsvuetify.js

Using vuetify in single .html page


I'm working on a personal project where I'm trying to avoid a full npm build process and instead work within a single .html file that uses Vue 3 and Vuetify. Here's the full HTML (basically you can drop it into a file, open it in a browser, and see what I'm seeing):

<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css">
  <script type="importmap">
      {
        "imports": {
          "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js",
          "vuetify": "https://cdnjs.cloudflare.com/ajax/libs/vuetify/3.4.3/vuetify.esm.min.js"
        }
      }
    </script>
</head>
<body>
  <div id="app">
    <v-table>
      <thead>
        <tr>
          <th>Value</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="d in numbers" :key="d">
          <td>{{ d }}</td>
        </tr>
      </tbody>
    </v-table>
  </div>

  <script type="module">
    import { createApp, ref } from 'vue'
    import { createVuetify } from 'vuetify'

    const vuetify = createVuetify()
    const app = createApp({
      setup() {
        const numbers = ref([4, 5, 6])
        return { numbers }
      }
    })

    app.use(vuetify).mount('#app')
  </script>
</body>
</html>

and I can see that Vue starts up, I can see that the Vuetify assets are being fetched properly, but I get an error in the console that I think means something's happening out of order:

[Vue warn]: Property "d" was accessed during render but is not defined on instance. 
  at <VTable> 
  at <App>

My guess is that the template is trying to render somehow before the setup() script populates data? Is what I'm trying to do possible?

One other thing that seems odd is that when I don't try to use data and instead just create a simple table with v-table, eg.

<v-table>
  <thead>
    <tr>
      <th>Col 1</th>
      <th>Col 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>R1C1</td>
      <td>R1C2</td>
    </tr>
  </tbody>
</v-table>

the rendered output is just <table> Col 1 Col 2 R1C1 R1C2 </table>, but there are no errors in the console. Worth noting that if I remove Vuetify from the mix and just use regular table tags, my table is created properly. It seems to happen only when Vuetify tries to render the v-table component.


Solution

  • When you put Vue template code into the <div id="app"> directly, it will be processed by the browser before Vue can get to it. When table elements like thead, tbody, etc. are used outside a table, the browser kicks them out, leaving you with this:

    <v-table>{{ d }}</v-table>
    

    Since d from the v-for was removed along with the tr, you end up with a warning and a broken table.


    There are two ways to resolve the issue, either move the template code into Vue setup and leave the app mount point empty:

    <div id="app"></div>
    

    and

      <script type="module">
        ...
        const app = createApp({
          template: `
            <v-table>
              rest of the table code...
            </v-table>
          `,
          setup() {
            const numbers = ref([4, 5, 6])
            return { numbers }
          }
        })
        ...
    

    Alternatively, you can use a table element instead of the v-table and have Vue replace it later on using the is attribute:

      <div id="app">
        <table is="vue:v-table">
          rest of the table code...
        </table>
      </div>
    

    There are other issues when not using templates, have a look at the in-DOM Template Parsing Caveats section of the docs