diff --git a/code/renderers/vue3/src/docs/sourceDecorator.test.ts b/code/renderers/vue3/src/docs/sourceDecorator.test.ts
index d3189e9eb767..40d5f4a8da64 100644
--- a/code/renderers/vue3/src/docs/sourceDecorator.test.ts
+++ b/code/renderers/vue3/src/docs/sourceDecorator.test.ts
@@ -1,95 +1,302 @@
 import { describe, expect, test } from '@jest/globals';
 import type { Args } from '@storybook/types';
-import { generateSource } from './sourceDecorator';
+
+import type { ArgsType } from 'jest-mock';
+import {
+  mapAttributesAndDirectives,
+  generateAttributesSource,
+  attributeSource,
+  htmlEventAttributeToVueEventAttribute as htmlEventToVueEvent,
+} from './sourceDecorator';
 
 expect.addSnapshotSerializer({
   print: (val: any) => val,
   test: (val: unknown) => typeof val === 'string',
 });
-function generateArgTypes(args: Args, slotProps: string[] | undefined) {
-  return Object.keys(args).reduce((acc, prop) => {
-    acc[prop] = { table: { category: slotProps?.includes(prop) ? 'slots' : 'props' } };
-    return acc;
-  }, {} as Record<string, any>);
-}
-function generateForArgs(args: Args, slotProps: string[] | undefined = undefined) {
-  return generateSource({ name: 'Component' }, args, generateArgTypes(args, slotProps), true);
-}
-function generateMultiComponentForArgs(args: Args, slotProps: string[] | undefined = undefined) {
-  return generateSource(
-    [{ name: 'Component' }, { name: 'Component' }],
-    args,
-    generateArgTypes(args, slotProps),
-    true
-  );
-}
 
-describe('generateSource Vue3', () => {
-  test('boolean true', () => {
-    expect(generateForArgs({ booleanProp: true })).toMatchInlineSnapshot(
-      `<Component :boolean-prop='booleanProp'/>`
-    );
+describe('Vue3: sourceDecorator->mapAttributesAndDirective()', () => {
+  test('camelCase boolean Arg', () => {
+    expect(mapAttributesAndDirectives({ camelCaseBooleanArg: true })).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: camel-case-boolean-arg,
+            loc: Object {
+              source: camel-case-boolean-arg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: true,
+            },
+          },
+          loc: Object {
+            source: :camel-case-boolean-arg="true",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('boolean false', () => {
-    expect(generateForArgs({ booleanProp: false })).toMatchInlineSnapshot(
-      `<Component :boolean-prop='booleanProp'/>`
-    );
+  test('camelCase string Arg', () => {
+    expect(mapAttributesAndDirectives({ camelCaseStringArg: 'foo' })).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: camel-case-string-arg,
+            loc: Object {
+              source: camel-case-string-arg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: foo,
+            },
+          },
+          loc: Object {
+            source: camel-case-string-arg="foo",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('null property', () => {
-    expect(generateForArgs({ nullProp: null })).toMatchInlineSnapshot(
-      `<Component :null-prop='nullProp'/>`
-    );
+  test('boolean arg', () => {
+    expect(mapAttributesAndDirectives({ booleanarg: true })).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: booleanarg,
+            loc: Object {
+              source: booleanarg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: true,
+            },
+          },
+          loc: Object {
+            source: :booleanarg="true",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('string property', () => {
-    expect(generateForArgs({ stringProp: 'mystr' })).toMatchInlineSnapshot(
-      `<Component :string-prop='stringProp'/>`
-    );
+  test('string arg', () => {
+    expect(mapAttributesAndDirectives({ stringarg: 'bar' })).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: stringarg,
+            loc: Object {
+              source: stringarg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: bar,
+            },
+          },
+          loc: Object {
+            source: stringarg="bar",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('number property', () => {
-    expect(generateForArgs({ numberProp: 42 })).toMatchInlineSnapshot(
-      `<Component :number-prop='numberProp'/>`
-    );
+  test('number arg', () => {
+    expect(mapAttributesAndDirectives({ numberarg: 2023 })).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: numberarg,
+            loc: Object {
+              source: numberarg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: 2023,
+            },
+          },
+          loc: Object {
+            source: :numberarg="2023",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('object property', () => {
-    expect(generateForArgs({ objProp: { x: true } })).toMatchInlineSnapshot(
-      `<Component :obj-prop='objProp'/>`
-    );
+  test('camelCase boolean, string, and number Args', () => {
+    expect(
+      mapAttributesAndDirectives({
+        camelCaseBooleanArg: true,
+        camelCaseStringArg: 'foo',
+        cameCaseNumberArg: 2023,
+      })
+    ).toMatchInlineSnapshot(`
+      Array [
+        Object {
+          arg: Object {
+            content: camel-case-boolean-arg,
+            loc: Object {
+              source: camel-case-boolean-arg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: true,
+            },
+          },
+          loc: Object {
+            source: :camel-case-boolean-arg="true",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+        Object {
+          arg: Object {
+            content: camel-case-string-arg,
+            loc: Object {
+              source: camel-case-string-arg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: foo,
+            },
+          },
+          loc: Object {
+            source: camel-case-string-arg="foo",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+        Object {
+          arg: Object {
+            content: came-case-number-arg,
+            loc: Object {
+              source: came-case-number-arg,
+            },
+          },
+          exp: Object {
+            isStatic: false,
+            loc: Object {
+              source: 2023,
+            },
+          },
+          loc: Object {
+            source: :came-case-number-arg="2023",
+          },
+          modifiers: Array [
+            ,
+          ],
+          name: bind,
+          type: 6,
+        },
+      ]
+    `);
   });
-  test('multiple properties', () => {
-    expect(generateForArgs({ a: 1, b: 2 })).toMatchInlineSnapshot(`<Component :a='a' :b='b'/>`);
+});
+
+describe('Vue3: sourceDecorator->generateAttributesSource()', () => {
+  test('camelCase boolean Arg', () => {
+    expect(
+      generateAttributesSource(
+        mapAttributesAndDirectives({ camelCaseBooleanArg: true }),
+        { camelCaseBooleanArg: true },
+        [{ camelCaseBooleanArg: { type: 'boolean' } }] as ArgsType<Args>
+      )
+    ).toMatchInlineSnapshot(`:camel-case-boolean-arg="true"`);
   });
-  test('1 slot property', () => {
-    expect(generateForArgs({ content: 'xyz', myProp: 'abc' }, ['content'])).toMatchInlineSnapshot(`
-      <Component :my-prop='myProp'>
-        {{ content }}
-      </Component>
-    `);
+  test('camelCase string Arg', () => {
+    expect(
+      generateAttributesSource(
+        mapAttributesAndDirectives({ camelCaseStringArg: 'foo' }),
+        { camelCaseStringArg: 'foo' },
+        [{ camelCaseStringArg: { type: 'string' } }] as ArgsType<Args>
+      )
+    ).toMatchInlineSnapshot(`camel-case-string-arg="foo"`);
   });
-  test('multiple slot property with second slot value not set', () => {
-    expect(generateForArgs({ content: 'xyz', myProp: 'abc' }, ['content', 'footer']))
-      .toMatchInlineSnapshot(`
-      <Component :my-prop='myProp'>
-        {{ content }}
-      </Component>
-    `);
+
+  test('camelCase boolean, string, and number Args', () => {
+    expect(
+      generateAttributesSource(
+        mapAttributesAndDirectives({
+          camelCaseBooleanArg: true,
+          camelCaseStringArg: 'foo',
+          cameCaseNumberArg: 2023,
+        }),
+        {
+          camelCaseBooleanArg: true,
+          camelCaseStringArg: 'foo',
+          cameCaseNumberArg: 2023,
+        },
+        [] as ArgsType<Args>
+      )
+    ).toMatchInlineSnapshot(
+      `:camel-case-boolean-arg="true" camel-case-string-arg="foo" :came-case-number-arg="2023"`
+    );
   });
-  test('multiple slot property with second slot value is set', () => {
-    expect(generateForArgs({ content: 'xyz', footer: 'foo', myProp: 'abc' }, ['content', 'footer']))
-      .toMatchInlineSnapshot(`
-      <Component :my-prop='myProp'>
-        <template #content>{{ content }}</template>
-        <template #footer>{{ footer }}</template>
-      </Component>
-    `);
+});
+
+describe('Vue3: sourceDecorator->attributeSoure()', () => {
+  test('camelCase boolean Arg', () => {
+    expect(attributeSource('stringArg', 'foo')).toMatchInlineSnapshot(`stringArg="foo"`);
   });
-  // test mutil components
-  test('multi component with boolean true', () => {
-    expect(generateMultiComponentForArgs({ booleanProp: true })).toMatchInlineSnapshot(`
-      <Component :boolean-prop='booleanProp'/>
-      <Component :boolean-prop='booleanProp'/>
-    `);
+
+  test('html event attribute should convert to vue event directive', () => {
+    expect(attributeSource('onClick', () => {})).toMatchInlineSnapshot(`v-on:click='()=>({})'`);
+    expect(attributeSource('onclick', () => {})).toMatchInlineSnapshot(`v-on:click='()=>({})'`);
+  });
+  test('normal html attribute should not convert to vue event directive', () => {
+    expect(attributeSource('on-click', () => {})).toMatchInlineSnapshot(`on-click='()=>({})'`);
   });
-  test('component is not set', () => {
-    expect(generateSource(null, {}, {})).toBeNull();
+  test('htmlEventAttributeToVueEventAttribute  onEv => v-on:', () => {
+    const htmlEventAttributeToVueEventAttribute = (attribute: string) => {
+      return htmlEventToVueEvent(attribute);
+    };
+    expect(/^on[A-Za-z]/.test('onClick')).toBeTruthy();
+    expect(htmlEventAttributeToVueEventAttribute('onclick')).toMatchInlineSnapshot(`v-on:click`);
+    expect(htmlEventAttributeToVueEventAttribute('onClick')).toMatchInlineSnapshot(`v-on:click`);
+    expect(htmlEventAttributeToVueEventAttribute('onChange')).toMatchInlineSnapshot(`v-on:change`);
+    expect(htmlEventAttributeToVueEventAttribute('onFocus')).toMatchInlineSnapshot(`v-on:focus`);
+    expect(htmlEventAttributeToVueEventAttribute('on-focus')).toMatchInlineSnapshot(`on-focus`);
   });
 });
diff --git a/code/renderers/vue3/src/docs/sourceDecorator.ts b/code/renderers/vue3/src/docs/sourceDecorator.ts
index 59ac746ae027..007980f1ff14 100644
--- a/code/renderers/vue3/src/docs/sourceDecorator.ts
+++ b/code/renderers/vue3/src/docs/sourceDecorator.ts
@@ -1,23 +1,32 @@
+/* eslint-disable no-eval */
+/* eslint-disable import/no-extraneous-dependencies */
 /* eslint-disable no-underscore-dangle */
-import { addons, useEffect } from '@storybook/preview-api';
+import { addons } from '@storybook/preview-api';
 import type { ArgTypes, Args, StoryContext, Renderer } from '@storybook/types';
 
 import { SourceType, SNIPPET_RENDERED } from '@storybook/docs-tools';
 
-// eslint-disable-next-line import/no-extraneous-dependencies
-import parserHTML from 'prettier/parser-html';
+import type {
+  ElementNode,
+  AttributeNode,
+  DirectiveNode,
+  TextNode,
+  InterpolationNode,
+  TemplateChildNode,
+} from '@vue/compiler-core';
+import { baseParse } from '@vue/compiler-core';
+import type { ConcreteComponent, FunctionalComponent, VNode } from 'vue';
+import { h, isVNode, watch } from 'vue';
+import { kebabCase } from 'lodash';
+import {
+  attributeSource,
+  htmlEventAttributeToVueEventAttribute,
+  omitEvent,
+  evalExp,
+  replaceValueWithRef,
+  generateExpression,
+} from './utils';
 
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { isArray } from '@vue/shared';
-import { toRaw } from 'vue';
-
-type ArgEntries = [string, any][];
-type Attribute = {
-  name: string;
-  value: string;
-  sourceSpan?: any;
-  valueSpan?: any;
-} & Record<string, any>;
 /**
  * Check if the sourcecode should be generated.
  *
@@ -26,6 +35,7 @@ type Attribute = {
 const skipSourceRender = (context: StoryContext<Renderer>) => {
   const sourceParams = context?.parameters.docs?.source;
   const isArgsStory = context?.parameters.__isArgsStory;
+  const isDocsViewMode = context?.viewMode === 'docs';
 
   // always render if the user forces it
   if (sourceParams?.type === SourceType.DYNAMIC) {
@@ -34,92 +44,94 @@ const skipSourceRender = (context: StoryContext<Renderer>) => {
 
   // never render if the user is forcing the block to render code, or
   // if the user provides code, or if it's not an args story.
-  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;
+  return (
+    !isDocsViewMode || !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE
+  );
 };
 
-/**
- * Extract a component name.
- *
- * @param component Component
- */
-function getComponentNameAndChildren(component: any): {
-  name: string | null;
-  children: any;
-  attributes: any;
-} {
-  return {
-    name: component?.name || component?.__name || component?.__docgenInfo?.__name || null,
-    children: component?.children || null,
-    attributes: component?.attributes || component?.attrs || null,
-  };
-}
 /**
  *
  * @param _args
  * @param argTypes
  * @param byRef
  */
-function generateAttributesSource(_args: Args, argTypes: ArgTypes, byRef?: boolean): string {
-  // create a copy of the args object to avoid modifying the original
-  const args = { ...toRaw(_args) };
-  // filter out keys that are children or slots, and convert event keys to the proper format
-  const argsKeys = Object.keys(args)
-    .filter(
-      (key: any) =>
-        ['children', 'slots'].indexOf(argTypes[key]?.table?.category) === -1 || !argTypes[key] // remove slots and children
-    )
-    .map((key) => {
-      const akey =
-        argTypes[key]?.table?.category !== 'events' // is event
-          ? key
-              .replace(/([A-Z])/g, '-$1')
-              .replace(/^on-/, 'v-on:')
-              .replace(/^:/, '')
-              .toLowerCase()
-          : `v-on:${key}`;
-      args[akey] = args[key];
-      return akey;
+export function generateAttributesSource(
+  tempArgs: (AttributeNode | DirectiveNode)[],
+  args: Args,
+  argTypes: ArgTypes,
+  byRef?: boolean
+): string {
+  return Object.keys(tempArgs)
+    .map((key: any) => {
+      const source = tempArgs[key].loc.source.replace(/\$props/g, 'args');
+      const argKey = (tempArgs[key] as DirectiveNode).arg?.loc.source;
+      return byRef && argKey
+        ? replaceValueWithRef(source, args, argKey)
+        : evalExp(source, omitEvent(args));
     })
-    .filter((key, index, self) => self.indexOf(key) === index); // remove duplicated keys
-
-  const camelCase = (str: string) => str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
-  const source = argsKeys
-    .map((key) =>
-      generateAttributeSource(
-        byRef && !key.includes(':') ? `:${key}` : key,
-        byRef && !key.includes(':') ? camelCase(key) : args[key],
-        argTypes[key]
-      )
-    )
     .join(' ');
-
-  return source;
 }
-
-function generateAttributeSource(
-  key: string,
-  value: Args[keyof Args],
-  argType: ArgTypes[keyof ArgTypes]
-): string {
-  if (!value) {
-    return '';
-  }
-
-  if (value === true) {
-    return key;
-  }
-
-  if (key.startsWith('v-on:')) {
-    return `${key}='() => {}'`;
-  }
-
-  if (typeof value === 'string') {
-    return `${key}='${value}'`;
-  }
-
-  return `:${key}='${JSON.stringify(value)}'`;
+/**
+ * map attributes and directives
+ * @param props
+ */
+function mapAttributesAndDirectives(props: Args) {
+  const tranformKey = (key: string) => (key.startsWith('on') ? key : kebabCase(key));
+  return Object.keys(props).map(
+    (key) =>
+      ({
+        name: 'bind',
+        type: ['v-', '@', 'v-on'].includes(key) ? 7 : 6, // 6 is attribute, 7 is directive
+        arg: { content: tranformKey(key), loc: { source: tranformKey(key) } }, // attribute name or directive name (v-bind, v-on, v-model)
+        loc: { source: attributeSource(tranformKey(key), props[key]) }, // attribute value or directive value
+        exp: { isStatic: false, loc: { source: props[key] } }, // directive expression
+        modifiers: [''],
+      } as unknown as AttributeNode)
+  );
 }
+/**
+ *  map slots
+ * @param slotsArgs
+ */
+function mapSlots(
+  slotsArgs: Args,
+  generateComponentSource: any,
+  slots: { name: string; scoped?: boolean; bindings?: { name: string }[] }[]
+): TextNode[] {
+  return Object.keys(slotsArgs).map((key) => {
+    const slot = slotsArgs[key];
+    let slotContent = '';
+
+    const scropedArgs = slots
+      .find((s) => s.name === key && s.scoped)
+      ?.bindings?.map((b) => b.name)
+      .join(',');
+
+    if (typeof slot === 'function') {
+      slotContent = generateExpression(slot);
+    }
+    if (isVNode(slot)) {
+      slotContent = generateComponentSource(slot);
+    }
 
+    if (typeof slot === 'object' && !isVNode(slot)) {
+      slotContent = JSON.stringify(slot);
+    }
+    const bindingsString = scropedArgs ? `="{${scropedArgs}}"` : '';
+    slotContent = slot ? `<template #${key}${bindingsString}>${slotContent}</template>` : ``;
+
+    return {
+      type: 2,
+      content: slotContent,
+      loc: {
+        source: slotContent,
+        start: { offset: 0, line: 1, column: 0 },
+        end: { offset: 0, line: 1, column: 0 },
+      },
+    };
+  });
+  // TODO: handle other cases (array, object, html,etc)
+}
 /**
  *
  * @param args generate script setup from args
@@ -137,35 +149,34 @@ function generateScriptSetup(args: Args, argTypes: ArgTypes, components: any[]):
   return `<script lang='ts' setup>${scriptLines.join('\n')}</script>`;
 }
 /**
- * get component templates one or more
+ * get template components one or more
  * @param renderFn
  */
-function getTemplates(renderFn: any): [] {
+function getTemplateComponents(
+  renderFn: any,
+  context?: StoryContext<Renderer>
+): (TemplateChildNode | VNode)[] {
   try {
-    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-    // @ts-ignore
-    const ast = parserHTML.parsers.vue.parse(renderFn.toString());
-    let components = ast.children?.filter(
-      ({ name: _name = '', type: _type = '' }) =>
-        _name && !['template', 'script', 'style', 'slot'].includes(_name) && _type === 'element'
-    );
-    if (!isArray(components)) {
-      return [];
-    }
-    components = components.map(
-      ({ attrs: attributes = [], name: Name = '', children: Children = [] }) => {
-        return {
-          name: Name,
-          attrs: attributes,
-          children: Children,
-        };
-      }
-    );
-    return components;
+    const originalStoryFn = renderFn;
+
+    const storyFn = originalStoryFn ? originalStoryFn(context?.args, context) : context?.component;
+    const story = typeof storyFn === 'function' ? storyFn() : storyFn;
+
+    const { template } = story;
+
+    if (!template) return [h(story, context?.args)];
+    return getComponents(template);
   } catch (e) {
-    // console.error(e);
+    console.log('error', e);
+    return [];
   }
-  return [];
+}
+
+function getComponents(template: string): (TemplateChildNode | VNode)[] {
+  const ast = baseParse(template);
+  const components = ast?.children;
+  if (!components) return [];
+  return components;
 }
 
 /**
@@ -176,141 +187,133 @@ function getTemplates(renderFn: any): [] {
  * @param argTypes ArgTypes
  * @param slotProp Prop used to simulate a slot
  */
-export function generateSource(
-  compOrComps: any,
-  args: Args,
-  argTypes: ArgTypes,
-  byRef?: boolean | undefined
-): string | null {
-  if (!compOrComps) return null;
-  const generateComponentSource = (component: any): string | null => {
-    const { name, children, attributes } = getComponentNameAndChildren(component);
 
-    if (!name) {
-      return '';
+export function generateTemplateSource(
+  componentOrNodes: (ConcreteComponent | TemplateChildNode)[] | TemplateChildNode | VNode,
+  { args, argTypes }: { args: Args; argTypes: ArgTypes },
+  byRef = false
+) {
+  const isElementNode = (node: any) => node && node.type === 1;
+  const isInterpolationNode = (node: any) => node && node.type === 5;
+  const isTextNode = (node: any) => node && node.type === 2;
+
+  const generateComponentSource = (
+    componentOrNode: ConcreteComponent | TemplateChildNode | VNode
+  ) => {
+    if (isElementNode(componentOrNode)) {
+      const { tag: name, props: attributes, children } = componentOrNode as ElementNode;
+      const childSources: string =
+        typeof children === 'string'
+          ? children
+          : children.map((child: TemplateChildNode) => generateComponentSource(child)).join('');
+      const props = generateAttributesSource(attributes, args, argTypes, byRef);
+
+      return childSources === ''
+        ? `<${name} ${props} />`
+        : `<${name} ${props}>${childSources}</${name}>`;
     }
 
-    const argsIn = attributes ? getArgsInAttrs(args, attributes) : args; // keep only args that are in attributes
-    const props = generateAttributesSource(argsIn, argTypes, byRef);
-    const slotArgs = Object.entries(argsIn).filter(
-      ([arg]) => argTypes[arg]?.table?.category === 'slots'
-    );
-    const slotProps = Object.entries(argTypes).filter(
-      ([arg]) => argTypes[arg]?.table?.category === 'slots'
-    );
-    if (slotArgs && slotArgs.length > 0) {
-      const namedSlotContents = createNamedSlots(slotArgs, slotProps, byRef);
-      return `<${name} ${props}>\n${namedSlotContents}\n</${name}>`;
+    if (isTextNode(componentOrNode)) {
+      const { content } = componentOrNode as TextNode;
+      return content;
     }
-
-    if (children && children.length > 0) {
-      const childrenSource = children.map((child: any) => {
-        return generateSource(
-          typeof child.value === 'string' ? getTemplates(child.value) : child.value,
-          args,
-          argTypes,
-          byRef
-        );
-      });
-
-      if (childrenSource.join('').trim() === '') return `<${name} ${props}/>`;
-
-      const isNativeTag =
-        name.includes('template') ||
-        name.match(/^[a-z]/) ||
-        (name === 'Fragment' && !name.includes('-'));
-
-      return `<${name} ${isNativeTag ? '' : props}>\n${childrenSource}\n</${name}>`;
+    if (isInterpolationNode(componentOrNode)) {
+      const { content } = componentOrNode as InterpolationNode;
+      const expValue = evalExp(content.loc.source, args);
+      if (expValue === content.loc.source) return `{{${expValue}}}`;
+      return eval(expValue);
+    }
+    if (isVNode(componentOrNode)) {
+      const vnode = componentOrNode as VNode;
+      const { props, type, children } = vnode;
+      const slotsProps = typeof children === 'string' ? undefined : (children as Args);
+      const componentSlots = (type as any)?.__docgenInfo?.slots;
+
+      const attrsProps = slotsProps
+        ? Object.fromEntries(
+            Object.entries(props ?? {})
+              .filter(([key, value]) => !slotsProps[key] && !['class', 'style'].includes(key))
+              .map(([key, value]) => [key, value])
+          )
+        : props;
+      const attributes = mapAttributesAndDirectives(attrsProps ?? {});
+      const slotArgs = Object.fromEntries(
+        Object.entries(props ?? {}).filter(([key, value]) => slotsProps?.[key])
+      );
+      // eslint-disable-next-line no-nested-ternary
+      const childSources: string = children
+        ? typeof children === 'string'
+          ? children
+          : mapSlots(slotArgs as Args, generateComponentSource, componentSlots ?? [])
+              .map((child) => child.content)
+              .join('')
+        : '';
+      console.log(' vnode ', vnode, ' childSources ', childSources, ' attributes ', attributes);
+      const name =
+        typeof type === 'string'
+          ? type
+          : (type as FunctionalComponent).name ||
+            (type as ConcreteComponent).__name ||
+            (type as any).__docgenInfo?.displayName;
+      const propsSource = generateAttributesSource(attributes, args, argTypes, byRef);
+      return childSources.trim() === ''
+        ? `<${name} ${propsSource}/>`
+        : `<${name} ${propsSource}>${childSources}</${name}>`;
     }
 
-    return `<${name} ${props}/>`;
+    return null;
   };
-  // get one component or multiple
-  const components = isArray(compOrComps) ? compOrComps : [compOrComps];
-
-  const source = Object.keys(components)
-    .map((key: any) => `${generateComponentSource(components[key])}`)
-    .join(`\n`);
-  return source;
-}
 
-/**
- * create Named Slots content in source
- * @param slotProps
- * @param slotArgs
- */
-
-function createNamedSlots(slotArgs: ArgEntries, slotProps: ArgEntries, byRef?: boolean) {
-  if (!slotArgs) return '';
-  const many = slotProps.length > 1;
-  return slotArgs
-    .map(([key, value]) => {
-      const content = !byRef ? JSON.stringify(value) : `{{ ${key} }}`;
-      return many ? `  <template #${key}>${content}</template>` : `  ${content}`;
-    })
-    .join('\n');
-}
-
-function getArgsInAttrs(args: Args, attributes: Attribute[]) {
-  return Object.keys(args).reduce((acc, prop) => {
-    if (attributes?.find((attr: any) => attr.name === 'v-bind')) {
-      acc[prop] = args[prop];
-    }
-    const attribute = attributes?.find(
-      (attr: any) => attr.name === prop || attr.name === `:${prop}`
-    );
-    if (attribute) {
-      acc[prop] = attribute.name === `:${prop}` ? args[prop] : attribute.value;
-    }
-    if (Object.keys(acc).length === 0) {
-      attributes?.forEach((attr: any) => {
-        acc[attr.name] = JSON.parse(JSON.stringify(attr.value));
-      });
-    }
-    return acc;
-  }, {} as Record<string, any>);
+  const componentsOrNodes = Array.isArray(componentOrNodes) ? componentOrNodes : [componentOrNodes];
+  const source = componentsOrNodes
+    .map((componentOrNode) => generateComponentSource(componentOrNode))
+    .join(' ');
+  return source || null;
 }
 
-/**
- * format prettier for vue
- * @param source
- */
-
 /**
  *  source decorator.
  * @param storyFn Fn
  * @param context  StoryContext
  */
 export const sourceDecorator = (storyFn: any, context: StoryContext<Renderer>) => {
-  const channel = addons.getChannel();
   const skip = skipSourceRender(context);
   const story = storyFn();
 
-  let source: string;
-
-  useEffect(() => {
-    if (!skip && source) {
-      const { id, unmappedArgs } = context;
-      channel.emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source, format: 'vue' });
-    }
-  });
-
-  if (skip) {
-    return story;
-  }
-
-  const { args = {}, component: ctxtComponent, argTypes = {} } = context || {};
-  const components = getTemplates(context?.originalStoryFn);
+  watch(
+    () => context.args,
+    () => {
+      if (!skip) {
+        generateSource(context);
+      }
+    },
+    { immediate: true, deep: true }
+  );
+  return story;
+};
 
-  const storyComponent = components.length ? components : ctxtComponent;
+export function generateSource(context: StoryContext<Renderer>) {
+  const channel = addons.getChannel();
+  const { args = {}, argTypes = {}, id } = context || {};
+  const storyComponents = getTemplateComponents(context?.originalStoryFn, context);
 
   const withScript = context?.parameters?.docs?.source?.withScriptSetup || false;
-  const generatedScript = withScript ? generateScriptSetup(args, argTypes, components) : '';
-  const generatedTemplate = generateSource(storyComponent, args, argTypes, withScript);
+  const generatedScript = withScript ? generateScriptSetup(args, argTypes, storyComponents) : '';
+  const generatedTemplate = generateTemplateSource(storyComponents, context, withScript);
 
   if (generatedTemplate) {
-    source = `${generatedScript}\n <template>\n ${generatedTemplate} \n</template>`;
+    const source = `${generatedScript}\n <template>\n ${generatedTemplate} \n</template>`;
+    channel.emit(SNIPPET_RENDERED, { id, args, source, format: 'vue' });
+    return source;
   }
-
-  return story;
+  return null;
+}
+// export local function for testing purpose
+export {
+  generateScriptSetup,
+  getTemplateComponents as getComponentsFromRenderFn,
+  getComponents as getComponentsFromTemplate,
+  mapAttributesAndDirectives,
+  attributeSource,
+  htmlEventAttributeToVueEventAttribute,
 };
diff --git a/code/renderers/vue3/src/docs/utils.ts b/code/renderers/vue3/src/docs/utils.ts
new file mode 100644
index 000000000000..707feb46e58f
--- /dev/null
+++ b/code/renderers/vue3/src/docs/utils.ts
@@ -0,0 +1,91 @@
+import type { Args } from '@storybook/types';
+import type { FunctionalComponent } from 'vue';
+
+/**
+ *  omit event args
+ * @param args
+ */
+const omitEvent = (args: Args): Args =>
+  args
+    ? Object.fromEntries(Object.entries(args).filter(([key, value]) => !key.startsWith('on')))
+    : {};
+
+const displayObject = (obj: any): string | boolean | number => {
+  if (obj && typeof obj === 'object') {
+    return `{${Object.keys(obj)
+      .map((key) => `${key}:${displayObject(obj[key])}`)
+      .join(',')}}`;
+  }
+  if (typeof obj === 'string') return `'${obj}'`;
+  return obj?.toString();
+};
+const htmlEventAttributeToVueEventAttribute = (key: string) => {
+  return /^on[A-Za-z]/.test(key) ? key.replace(/^on/, 'v-on:').toLowerCase() : key;
+};
+
+const directiveSource = (key: string, value: unknown) =>
+  key.includes('on')
+    ? `${htmlEventAttributeToVueEventAttribute(key)}='()=>({})'`
+    : `${key}="${value}"`;
+
+const attributeSource = (key: string, value: unknown, dynamic?: boolean) =>
+  // convert html event key to vue event key
+  ['boolean', 'number', 'object'].includes(typeof value) || // dynamic value
+  (dynamic && ['style', 'class'].includes(key)) // dynamic style or class
+    ? `:${key}="${displayObject(value)}"`
+    : directiveSource(key, value);
+
+const evalExp = (argExpValue: any, args: Args): any => {
+  let evalVal = argExpValue;
+  if (evalVal && /v-bind="(\w+)"/.test(evalVal))
+    return evalVal.replace(/"(\w+)"/g, `"${displayObject(args)}"`);
+
+  Object.keys(args).forEach((akey) => {
+    const regexMatch = new RegExp(`(\\w+)\\.${akey}`, 'g');
+    const regexTarget = new RegExp(`(\\w+)\\.${akey}`, 'g');
+    if (regexMatch.test(evalVal)) {
+      evalVal = evalVal.replace(regexTarget, displayObject(args[akey]));
+    }
+  });
+
+  return evalVal;
+};
+
+const replaceValueWithRef = (source: string, args: Args, ref: string) => {
+  const value = ref ? args[ref] : 'args';
+
+  const bindValue = () => {
+    const argsRef = Object.fromEntries(Object.entries(args).map(([key]) => [key, key]));
+    return (displayObject(argsRef) as string).replace(/'/g, '');
+  };
+
+  const regexMatch = new RegExp(`="${value}"`, 'g');
+  return source.replace(regexMatch, `="${ref ?? bindValue()}"`);
+};
+
+/**
+ *
+ * replace function curly brackets and return with empty string ex: () => { return `${text} , ${year}` } => `${text} , ${year}`
+ *
+ * @param slot
+ * @returns
+ *  */
+
+function generateExpression(slot: FunctionalComponent): string {
+  let body = slot.toString().split('=>')[1].trim().replace('return', '').trim();
+  if (body.startsWith('{') && body.endsWith('}')) {
+    body = body.substring(1, body.length - 1).trim();
+  }
+  return `{{${body}}}`;
+}
+
+export {
+  omitEvent,
+  displayObject,
+  htmlEventAttributeToVueEventAttribute,
+  directiveSource,
+  attributeSource,
+  evalExp,
+  replaceValueWithRef,
+  generateExpression,
+};
diff --git a/code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceDecorator.stories.ts b/code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceDecorator.stories.ts
new file mode 100644
index 000000000000..4a5a8613069e
--- /dev/null
+++ b/code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceDecorator.stories.ts
@@ -0,0 +1,46 @@
+import type { Meta, StoryObj } from '@storybook/vue3';
+
+import GlobalUsage from './GlobalUsage.vue';
+import GlobalSetup from './GlobalSetup.vue';
+
+const meta: Meta = {
+  component: GlobalUsage,
+  argTypes: {},
+  tags: ['autodocs'],
+} satisfies Meta<typeof GlobalUsage>;
+
+export default meta;
+type Story = StoryObj<typeof meta>;
+
+export const MultiComponents: Story = {
+  args: {
+    label: 'Button',
+    size: 'large',
+    backgroundColor: '#aa00ff',
+    btn1Args: { label: 'Button 10', size: 'small', backgroundColor: '#aa00ff' },
+  },
+  render(args: any) {
+    return {
+      components: { GlobalUsage, GlobalSetup },
+      setup() {
+        return { args };
+      },
+      template: `<div style="background-color:pink;opacity:0.9;padding:20px" >
+                  
+                  <div style="display:flex;gap:10px">
+                    <img src="https://user-images.githubusercontent.com/263385/199832481-bbbf5961-6a26-481d-8224-51258cce9b33.png" width="200" />  
+                    <GlobalUsage v-bind="args.btn1Args" />&nbsp;
+                  </div>
+                  <h2>Complex Story Custom template </h2> <br/> <hr/>
+                
+                <GlobalSetup  :label="args.label" />
+                <div style="margin:8px"><span style="font-size:28px;color:green">Multiple </span>
+                <span style="background-color:magenta;opacity:0.9;padding:8px"><i>Components</i></span></div>
+                <div style="display:flex;gap:10px">
+                  <GlobalUsage v-bind="args" />
+                  <GlobalUsage label="Static Label Dynamic color" :background-color="args.backgroundColor"/>  
+                </div>   
+               </div>`,
+    };
+  },
+};