How to make a table editable in Vue

Creating editable tables allows users to modify data directly within table cells, essential for admin panels and data management interfaces. As the creator of CoreUI with over 11 years of Vue development experience since 2014, I’ve built editable tables in countless enterprise applications. The most effective solution is to track which row is being edited and toggle between view and edit modes. This approach provides inline editing with clear save and cancel actions.

Use reactive state to track edit mode and create editable tables in Vue 3.

<template>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Age</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for='item in data' :key='item.id'>
        <template v-if='editingId === item.id'>
          <td><input v-model='editForm.name' type='text' /></td>
          <td><input v-model='editForm.email' type='email' /></td>
          <td><input v-model.number='editForm.age' type='number' /></td>
          <td>
            <button @click='saveEdit(item.id)'>Save</button>
            <button @click='cancelEdit'>Cancel</button>
          </td>
        </template>
        <template v-else>
          <td>{{ item.name }}</td>
          <td>{{ item.email }}</td>
          <td>{{ item.age }}</td>
          <td>
            <button @click='startEdit(item)'>Edit</button>
          </td>
        </template>
      </tr>
    </tbody>
  </table>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const editingId = ref(null)
    const editForm = ref({})

    const data = ref([
      { id: 1, name: 'John Doe', email: '[email protected]', age: 30 },
      { id: 2, name: 'Jane Smith', email: '[email protected]', age: 25 },
      { id: 3, name: 'Bob Johnson', email: '[email protected]', age: 35 }
    ])

    const startEdit = (item) => {
      editingId.value = item.id
      editForm.value = { ...item }
    }

    const saveEdit = (id) => {
      const index = data.value.findIndex(item => item.id === id)
      if (index !== -1) {
        data.value[index] = { ...editForm.value }
      }
      editingId.value = null
      editForm.value = {}
    }

    const cancelEdit = () => {
      editingId.value = null
      editForm.value = {}
    }

    return { data, editingId, editForm, startEdit, saveEdit, cancelEdit }
  }
}
</script>

The editingId ref tracks which row is currently being edited. When editing starts, the row data is copied to editForm to allow modifications without affecting the original until saved. The template conditionally renders either view mode or edit mode based on whether the row ID matches editingId. Save updates the data array while cancel simply clears the edit state.

Best Practice Note

This is the same editable table pattern we use in CoreUI Vue components for inline data editing. For production use, add validation before saving and implement an API call to persist changes to the server. Consider adding keyboard shortcuts like Enter to save and Escape to cancel for better user experience.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team