<p dir="auto"><code class="notranslate">Vue.extend()</code> works well but i think there is no way to extend the corresponding template without changing scope. Here is an example of what i'd like to achieve. <code class="notranslate">&lt;block&gt;</code> is like <code class="notranslate">&lt;slot&gt;</code> but i renamed it not to be confused with the current slot implementation</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const BaseForm = Vue.extend({
  template: `
    &lt;form&gt;
      &lt;block name=&quot;header&quot;&gt;
        &lt;h1&gt;{{ title }}&lt;/h1&gt;
      &lt;/block&gt;
      &lt;block name=&quot;content&quot;&gt;Form inputs go here&lt;/block&gt;
      &lt;block name=&quot;actions&quot;&gt;
        &lt;button @click=&quot;saveRecord&quot;&gt;Save&lt;/button&gt;
        &lt;button @click=&quot;deleteRecord&quot;&gt;Delete&lt;/button&gt;
      &lt;/block&gt;
    &lt;/form&gt;
  `,
  data () {
    return {
      title: 'Base Title',
      apiUrl: null,
      record: {}
    }
  },
  methods: {
    saveRecord () {
      // axios.post(this.apiUrl + this.record.id)...
    },
    deleteRecord () {
      // axios.delete(this.apiUrl + this.record.id)...
    }
  }
})

const PersonForm = BaseForm.extend({
  template: `
    &lt;extend&gt;
      &lt;div block=&quot;header&quot;&gt;
        {{ title }} From Person Form
        &lt;button @click=&quot;saveRecord&quot;&gt;Save from header&lt;/button&gt;
      &lt;/div&gt;
      &lt;div block=&quot;content&quot;&gt;
        &lt;input type=&quot;text&quot; v-model=&quot;record.name&quot; /&gt;
        &lt;input type=&quot;text&quot; v-model=&quot;record.age&quot; /&gt;
        &lt;button @click=&quot;incAge&quot;&gt;Increase age&lt;/button&gt;
      &lt;/div&gt;
   &lt;/extend&gt;
  `,
  data () {
    return {
      title: 'My Title',
      apiUrl: '/api/my/',
      record: {
        id: 1,
        name: '',
        age: 0
      }
    }
  },
  methods: {
    incAge () {
      this.record.age++
    }
  }
})"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-v">BaseForm</span> <span class="pl-c1">=</span> <span class="pl-v">Vue</span><span class="pl-kos">.</span><span class="pl-en">extend</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">template</span>: <span class="pl-s">`</span>
<span class="pl-s">    &lt;form&gt;</span>
<span class="pl-s">      &lt;block name="header"&gt;</span>
<span class="pl-s">        &lt;h1&gt;{{ title }}&lt;/h1&gt;</span>
<span class="pl-s">      &lt;/block&gt;</span>
<span class="pl-s">      &lt;block name="content"&gt;Form inputs go here&lt;/block&gt;</span>
<span class="pl-s">      &lt;block name="actions"&gt;</span>
<span class="pl-s">        &lt;button @click="saveRecord"&gt;Save&lt;/button&gt;</span>
<span class="pl-s">        &lt;button @click="deleteRecord"&gt;Delete&lt;/button&gt;</span>
<span class="pl-s">      &lt;/block&gt;</span>
<span class="pl-s">    &lt;/form&gt;</span>
<span class="pl-s">  `</span><span class="pl-kos">,</span>
  <span class="pl-en">data</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-kos">{</span>
      <span class="pl-c1">title</span>: <span class="pl-s">'Base Title'</span><span class="pl-kos">,</span>
      <span class="pl-c1">apiUrl</span>: <span class="pl-c1">null</span><span class="pl-kos">,</span>
      <span class="pl-c1">record</span>: <span class="pl-kos">{</span><span class="pl-kos">}</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">methods</span>: <span class="pl-kos">{</span>
    <span class="pl-en">saveRecord</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-c">// axios.post(this.apiUrl + this.record.id)...</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
    <span class="pl-en">deleteRecord</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-c">// axios.delete(this.apiUrl + this.record.id)...</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span>

<span class="pl-k">const</span> <span class="pl-v">PersonForm</span> <span class="pl-c1">=</span> <span class="pl-v">BaseForm</span><span class="pl-kos">.</span><span class="pl-en">extend</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">template</span>: <span class="pl-s">`</span>
<span class="pl-s">    &lt;extend&gt;</span>
<span class="pl-s">      &lt;div block="header"&gt;</span>
<span class="pl-s">        {{ title }} From Person Form</span>
<span class="pl-s">        &lt;button @click="saveRecord"&gt;Save from header&lt;/button&gt;</span>
<span class="pl-s">      &lt;/div&gt;</span>
<span class="pl-s">      &lt;div block="content"&gt;</span>
<span class="pl-s">        &lt;input type="text" v-model="record.name" /&gt;</span>
<span class="pl-s">        &lt;input type="text" v-model="record.age" /&gt;</span>
<span class="pl-s">        &lt;button @click="incAge"&gt;Increase age&lt;/button&gt;</span>
<span class="pl-s">      &lt;/div&gt;</span>
<span class="pl-s">   &lt;/extend&gt;</span>
<span class="pl-s">  `</span><span class="pl-kos">,</span>
  <span class="pl-en">data</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-kos">{</span>
      <span class="pl-c1">title</span>: <span class="pl-s">'My Title'</span><span class="pl-kos">,</span>
      <span class="pl-c1">apiUrl</span>: <span class="pl-s">'/api/my/'</span><span class="pl-kos">,</span>
      <span class="pl-c1">record</span>: <span class="pl-kos">{</span>
        <span class="pl-c1">id</span>: <span class="pl-c1">1</span><span class="pl-kos">,</span>
        <span class="pl-c1">name</span>: <span class="pl-s">''</span><span class="pl-kos">,</span>
        <span class="pl-c1">age</span>: <span class="pl-c1">0</span>
      <span class="pl-kos">}</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">methods</span>: <span class="pl-kos">{</span>
    <span class="pl-en">incAge</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">record</span><span class="pl-kos">.</span><span class="pl-c1">age</span><span class="pl-c1">++</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">So js is merged as usual but then the base template blocks are replaced with the new ones when compiling the template. So everything works within the same scope.<br>
<code class="notranslate">&lt;block&gt;</code> and <code class="notranslate">&lt;extend&gt;</code> can be changed with different words/options in the api</p>
<p dir="auto">Does this make sense? Or is there a better way to do it? Or is it not intact with Vue principles?</p>
<p dir="auto">The end results should be:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="{
  template: `
    &lt;form&gt;
      &lt;div&gt;
        {{ title }} From Person Form
        &lt;button @click=&quot;saveRecord&quot;&gt;Save from header&lt;/button&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;input type=&quot;text&quot; v-model=&quot;record.name&quot; /&gt;
        &lt;input type=&quot;text&quot; v-model=&quot;record.age&quot; /&gt;
        &lt;button @click=&quot;incAge&quot;&gt;Increase age&lt;/button&gt;
      &lt;/div&gt;
      &lt;button @click=&quot;saveRecord&quot;&gt;Save&lt;/button&gt;
      &lt;button @click=&quot;deleteRecord&quot;&gt;Delete&lt;/button&gt;
    &lt;/form&gt;
  `,
  data () {
    return {
      title: 'My Title',
      apiUrl: '/api/my/',
      record: {
        id: 1,
        name: '',
        age: 0
      }
    }
  },
  methods: {
    incAge () {
      this.record.age++
    },
    saveRecord () {
      // axios.post(this.apiUrl + this.record.id)...
    },
    deleteRecord () {
      // axios.delete(this.apiUrl + this.record.id)...
    }
  }
}"><pre class="notranslate"><span class="pl-kos">{</span>
  <span class="pl-c1">template</span>: <span class="pl-s">`</span>
<span class="pl-s">    &lt;form&gt;</span>
<span class="pl-s">      &lt;div&gt;</span>
<span class="pl-s">        {{ title }} From Person Form</span>
<span class="pl-s">        &lt;button @click="saveRecord"&gt;Save from header&lt;/button&gt;</span>
<span class="pl-s">      &lt;/div&gt;</span>
<span class="pl-s">      &lt;div&gt;</span>
<span class="pl-s">        &lt;input type="text" v-model="record.name" /&gt;</span>
<span class="pl-s">        &lt;input type="text" v-model="record.age" /&gt;</span>
<span class="pl-s">        &lt;button @click="incAge"&gt;Increase age&lt;/button&gt;</span>
<span class="pl-s">      &lt;/div&gt;</span>
<span class="pl-s">      &lt;button @click="saveRecord"&gt;Save&lt;/button&gt;</span>
<span class="pl-s">      &lt;button @click="deleteRecord"&gt;Delete&lt;/button&gt;</span>
<span class="pl-s">    &lt;/form&gt;</span>
<span class="pl-s">  `</span><span class="pl-kos">,</span>
  <span class="pl-en">data</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-kos">{</span>
      <span class="pl-c1">title</span>: <span class="pl-s">'My Title'</span><span class="pl-kos">,</span>
      <span class="pl-c1">apiUrl</span>: <span class="pl-s">'/api/my/'</span><span class="pl-kos">,</span>
      <span class="pl-c1">record</span>: <span class="pl-kos">{</span>
        <span class="pl-c1">id</span>: <span class="pl-c1">1</span><span class="pl-kos">,</span>
        <span class="pl-c1">name</span>: <span class="pl-s">''</span><span class="pl-kos">,</span>
        <span class="pl-c1">age</span>: <span class="pl-c1">0</span>
      <span class="pl-kos">}</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">methods</span>: <span class="pl-kos">{</span>
    <span class="pl-en">incAge</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">record</span><span class="pl-kos">.</span><span class="pl-c1">age</span><span class="pl-c1">++</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
    <span class="pl-en">saveRecord</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-c">// axios.post(this.apiUrl + this.record.id)...</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
    <span class="pl-en">deleteRecord</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-c">// axios.delete(this.apiUrl + this.record.id)...</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<h3 dir="auto">What problem does this feature solve?</h3>
<p dir="auto"><code class="notranslate">&lt;template&gt; &lt;span&gt;&lt;/span&gt; &lt;span&gt;&lt;/span&gt; &lt;/template&gt;</code></p>
<h3 dir="auto">What does the proposed API look like?</h3>
<p dir="auto"><code class="notranslate">&lt;template&gt; &lt;&gt; &lt;span&gt;&lt;/span&gt; &lt;span&gt;&lt;/span&gt; &lt;/&gt; &lt;/template&gt;</code></p>