Here's the list of fixes made to your original code to make it working:
Fix 1 — Moved the script to the bottom of <body> and removed type="module" and defer
The script was in <head> with type="module", which caused timing and scoping issues with the UMD globals (PrimeVue, PrimeUIX) loaded via CDN. Placing the script at the bottom of <body> guarantees the CDN libraries and the DOM are already available when the app initialises.
Reference: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#script_loading_strategies
Fix 2 — Fixed the :pt structure (table was nested inside column)
table and column are sibling keys in the passthrough object, not parent/child. Having table inside column meant the min-width style was silently ignored.
Reference: https://primevue.org/datatable/#pt.props.table
Fix 3 — Used edit-mode instead of editMode
In a plain HTML file, the browser lowercases all attribute names before Vue sees them, so editMode becomes editmode and Vue doesn't recognise it as the correct prop. Kebab-case (edit-mode) survives the browser's lowercasing. This was the main reason cell editing wasn't working.
Reference: https://vuejs.org/guide/essentials/component-basics#in-dom-template-parsing-caveats
Fix 4 — The bare <template> wrapper
Vue treats a <template> with no directive as transparent and renders through it correctly. It's pointless but harmless.
Fix 5 — Added phases bogus object in place of empty array
Since we needed a populated table, I added a populated array as the value of phases and commented this.fetchData() in mounted()
This is the fixed demo:
<html>
<head>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/primevue/umd/primevue.min.js"></script>
<script src="https://unpkg.com/@primeuix/themes/umd/aura.js"></script>
</head>
<body>
<div id="app">
<h1>Phase List</h1>
<p-datatable :value="phases" edit-mode="cell" @cell-edit-complete="onCellEditComplete"
:pt="{
table: { style: 'min-width: 50rem' },
column: {
bodycell: ({ state }) => ({
class: [{ '!py-0': state['d_editing'] }]
})
}
}"
>
<p-column v-for="col of columns" :key="col.field" :field="col.field" :header="col.header" style="width: 25%">
<template #body="{ data, field }">
[[ data[field] ]]
</template>
<template #editor="{ data, field }">
<p-inputtext v-model="data[field]" autofocus fluid />
</template>
</p-column>
</p-datatable>
<input type="button" value="Refresh" @click="fetchData()" />
</div>
<script defer>
const { createApp, ref } = Vue;
const app = createApp({
data() {
const date = ref();
return {
columns:[
{ field:"id", header:"Code" },
{ field:"name", header:"Name"},
],
phases: [
{ id: 1, name: 'Phase One' },
{ id: 2, name: 'Phase Two' },
{ id: 3, name: 'Phase Three' },
],
}
},
delimiters: ['[[',']]'],
methods: {
onCellEditComplete(e) {
},
async fetchData() {
this.phases = []
try {
const res = await fetch(`/phases`)
if (res.ok) this.phases = await res.json()
} catch(error) {
console.error("There was an error!", error);
}
},
renderData() {
}
},
mounted() {
//this.fetchData();
},
watch: {
phases() {
for(var i = 0; i < this.phases.length; i++) {
this.phases[i]["url"] = "/phases/" + this.phases[i].id
}
this.renderData()
}
}
})
app.use( PrimeVue.Config, { theme: { preset: PrimeUIX.Themes.Aura } });
app.component('p-column', PrimeVue.Column);
app.component('p-inputtext', PrimeVue.InputText);
app.component('p-datatable', PrimeVue.DataTable);
app.mount('#app');
</script>
</body>
</html>