[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"home-latest-articles":3},[4,58,105],{"title":5,"slug":6,"excerpt":7,"content":8,"author":9,"author_bio":10,"published_at":11,"updated_at":12,"is_featured":13,"is_external":14,"banner_image":15,"reading_time":16,"toc":17,"official_docs":40,"category":44,"tags":47,"meta":15},"PHP Attributes in Laravel 13 — The Complete Guide","php-attributes-in-laravel-13-the-complete-guide","Laravel 13 doubles down on PHP's native Attribute system, letting you replace scattered configuration arrays, boot callbacks, and interface implementations with clean, colocated #[...] annotations directly on your classes and methods. This article explains what PHP Attributes are, why they matter, and walks through every place Laravel 13 uses them — with working code examples and direct links to the official docs.","\u003Ch2 id=\"what-are-attributes\">What Are PHP Attributes?\u003C/h2>\r\n\u003Cp>PHP 8.0 introduced \u003Cstrong>Attributes\u003C/strong> (sometimes called Annotations) as a first-class, native language feature. An Attribute is a structured, machine-readable piece of metadata you can attach to classes, methods, properties, parameters, constants, or functions using the \u003Ccode>#[...] \u003C/code>syntax.\u003C/p>\r\n\u003Cp>Before Attributes, frameworks like Laravel relied on docblock comments parsed at runtime, or required you to implement specific interfaces or define properties/methods in your classes. Attributes replace all of that with something the PHP engine understands natively &mdash; no reflection hacks required.\u003C/p>\r\n\u003Ch2 id=\"basic-anatomy-of-a-php-attribute\">Basic Anatomy of a PHP Attribute\u003C/h2>\r\n\u003Cpre class=\"language-php\">\u003Ccode>// 1. Define an Attribute class\r\n#[Attribute]\r\nclass MyRoute\r\n{\r\n    public function __construct(\r\n        public readonly string $path,\r\n        public readonly string $method = 'GET',\r\n    ) {}\r\n}\r\n\r\n// 2. Apply it to a class or method\r\n#[MyRoute(path: '/hello', method: 'GET')]\r\nfunction helloWorld(): string\r\n{\r\n    return 'Hello, World!';\r\n}\r\n\r\n// 3. Read it at runtime with Reflection\r\n$rf   = new ReflectionFunction('helloWorld');\r\n$attr = $rf-&gt;getAttributes(MyRoute::class)[0];\r\n$inst = $attr-&gt;newInstance(); // &rarr; MyRoute object\r\necho $inst-&gt;path;            // &rarr; /hello\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>Key facts to know:\u003C/p>\r\n\u003Cul>\r\n\u003Cli>Attributes are \u003Cstrong>zero-cost when not inspected\u003C/strong> - PHP does not instantiate them unless you call \u003Ccode>-&gt;newInstance()\u003C/code> via reflection.\u003C/li>\r\n\u003Cli>An Attribute class is just a regular PHP class decorated with \u003Ccode>#[Attribute].\u003C/code>\u003C/li>\r\n\u003Cli>You can restrict where an Attribute is allowed (class only, method only,&nbsp; etc.). Using the \u003Ccode>Attribute::TARGET_*\u003C/code> flags.\u003C/li>\r\n\u003Cli>Multiple Attributes can be stacked on the same target: \u003Ccode>#[Attr1] #[Attr2].\u003C/code>\u003Ccode>&nbsp;\u003C/code>\u003C/li>\r\n\u003C/ul>\r\n\u003Cblockquote>\r\n\u003Cp>\u003Cstrong>Laravel's strategy:\u003C/strong> Laravel reads your Attributes during the service-container boot phase or request lifecycle &mdash; so you write zero runtime code; the framework does the heavy lifting with Reflection under the hood.\u003C/p>\r\n\u003C/blockquote>\r\n\u003Ch2 id=\"why-laravel-is-going-all-in-on-attributes\">Why Laravel is going All-In On Attributes\u003C/h2>\r\n\u003Cp>Laravel's design philosophy has always been about expressiveness and reduced boilerplate. Attributes fit perfectly because they let you declare intent right next to the code that implements it, instead of spreading configuration across routes files, service providers, and constructors.\u003C/p>\r\n\u003Cp>Compare the \"old way\" vs. the \"Attribute way\" for middleware on a controller:\u003C/p>\r\n\u003Ch3 id=\"before-attributes-laravel-1011-style\">Before Attributes (Laravel 10/11 style)\u003C/h3>\r\n\u003Cpre class=\"language-php\">\u003Ccode>class CommentController extends Controller\r\n{\r\n    public function __construct()\r\n    {\r\n        // Had to define middleware in the constructor\r\n        $this-&gt;middleware('auth');\r\n        $this-&gt;middleware('subscribed')-&gt;only('store');\r\n    }\r\n}\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch3 id=\"after-attributes-laravel-13-style\">After Attributes (Laravel 13 style)\u003C/h3>\r\n\u003Cpre class=\"language-php\">\u003Ccode>#[Middleware('auth')]\r\nclass CommentController\r\n{\r\n    #[Middleware('subscribed')]\r\n    public function store(Post $post): Response\r\n    {\r\n        // Intent is immediately obvious here\r\n    }\r\n}\u003C/code>\u003C/pre>\r\n\u003Cp>The Attribute version is self-documenting &mdash; a developer reading the method immediately knows what middleware and policies apply, without jumping to a constructor or routes file.\u003C/p>\r\n\u003Chr>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch2 id=\"laravel-13-attributes\">Every Laravel 13 Attribute &mdash; Documented\u003C/h2>\r\n\u003Cp>Below is the complete, categorised reference. For each Attribute you'll find a description, code example, use case, and a link to the official Laravel 13 documentation page.\u003C/p>\r\n\u003Ch2 id=\"attributes-at-a-glance\">Attributes at a Glance\u003C/h2>\r\n\u003Ctable style=\"border-collapse: collapse; width: 100%; border-width: 1px; border-style: solid; height: 78.7812px;\" border=\"1\">\u003Ccolgroup>\u003Ccol style=\"width: 6.36445%;\">\u003Ccol style=\"width: 18.6302%;\">\u003Ccol style=\"width: 24.9973%;\">\u003Ccol style=\"width: 50.008%;\">\u003C/colgroup>\r\n\u003Ctbody>\r\n\u003Ctr style=\"height: 39.3906px;\">\r\n\u003Ctd>\u003Cstrong>#\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Cstrong>ATTRIBUTE\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Cstrong>AREA\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Cstrong>REPLACES\u003C/strong>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr style=\"height: 39.3906px;\">\r\n\u003Ctd>1\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Table]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$table\u003C/code>, \u003Ccode>$primaryKey\u003C/code>, $\u003Ccode>timestamps\u003C/code>...\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>2\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Fillable]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$fillable\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>3\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Guarded]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$guarded\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>4\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Unguarded]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>Model::unguard() \u003C/code>call\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>5\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Hiddem]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$hidden\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>6\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Visible]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$visible\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>7\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Appends]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$appends\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003Ctr>\r\n\u003Ctd>8\u003C/td>\r\n\u003Ctd>\u003Ccode>#[Casts]\u003C/code>\u003C/td>\r\n\u003Ctd>\u003Cstrong>Eloquent\u003C/strong>\u003C/td>\r\n\u003Ctd>\u003Ccode>$casts\u003C/code> / \u003Ccode>casts()\u003C/code>\u003C/td>\r\n\u003C/tr>\r\n\u003C/tbody>\r\n\u003C/table>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>","Shyam Sundar Bhattarai","Software Engineer & Technical Writer","2026-03-29T16:52:00.000000Z","2026-03-30T07:58:03.000000Z",true,false,null,3,[18,22,25,28,31,34,37],{"level":19,"text":20,"id":21},2,"What Are PHP Attributes?","what-are-php-attributes",{"level":19,"text":23,"id":24},"Basic Anatomy of a PHP Attribute","basic-anatomy-of-a-php-attribute",{"level":19,"text":26,"id":27},"Why Laravel is going All-In On Attributes","why-laravel-is-going-all-in-on-attributes",{"level":16,"text":29,"id":30},"Before Attributes (Laravel 10/11 style)","before-attributes-laravel-1011-style",{"level":16,"text":32,"id":33},"After Attributes (Laravel 13 style)","after-attributes-laravel-13-style",{"level":19,"text":35,"id":36},"Every Laravel 13 Attribute &mdash; Documented","every-laravel-13-attribute-mdash-documented",{"level":19,"text":38,"id":39},"Attributes at a Glance","attributes-at-a-glance",[41],{"title":42,"url":43},"Laravel","https://laravel.com/docs/13.x/eloquent",{"id":19,"name":45,"slug":46},"Backend","backend",[48,49,52,55],{"name":45,"slug":46},{"name":50,"slug":51},"Php","php",{"name":53,"slug":54},"Laravel 13","laravel-13",{"name":56,"slug":57},"New in 13.x","new-in-13x",{"title":59,"slug":60,"excerpt":61,"content":62,"author":9,"author_bio":15,"published_at":63,"updated_at":64,"is_featured":13,"is_external":14,"banner_image":65,"reading_time":16,"toc":66,"official_docs":91,"category":92,"tags":96,"meta":15},"Vue 3.4+ defineModel(): Simplifying Two-Way Binding","vue-3-4-definemodel-simplifying-two-way-binding","Simplify v-model in Vue 3.4 with defineModel(). Cut boilerplate, enable two-way binding, TypeScript support, and modifiers for cleaner code.","\u003Cp>Vue 3.4 introduced the \u003Ccode>defineModel()\u003C/code> macro, revolutionizing how developers handle two-way binding in custom components. This powerful addition to the Composition API significantly reduces boilerplate code while maintaining the same functionality as traditional \u003Ccode>v-model \u003C/code>implementations.\u003C/p>\r\n\u003Ch2 id=\"what-is-definemodel\">What is defineModel()?\u003C/h2>\r\n\u003Cp>\u003Ccode>defineModel()\u003C/code> is a compile-time macro that simplifies the creation of custom components supporting v-model directives. Before this version, you typically needed to manually emit \u003Ccode>update:modelValue\u003C/code> events and manage the \u003Ccode>modelValue\u003C/code> prop. defineModel streamlines this process, automatically handling prop declarations and event emissions behind the scenes.\u003C/p>\r\n\u003Ch2 id=\"the-problem-it-solves\">The Problem It Solves\u003C/h2>\r\n\u003Cp>Previously, implementing two-way binding required manual setup of&nbsp; props and emits:\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;!-- Old approach --&gt;\r\n&lt;template&gt;\r\n  &lt;input type=\"text\" @input=\"updateValue\" :value=\"modelValue\" /&gt;\r\n&lt;/template&gt;\r\n\r\n&lt;script setup&gt;\r\ndefineProps(['modelValue']);\r\nconst emit = defineEmits(['update:modelValue']);\r\n\r\nconst updateValue = (e) =&gt; {\r\n  const value = e.target.value;\r\n  emit('update:modelValue', value);\r\n};\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>With d\u003Ccode>efineModel()\u003C/code>, this becomes drastically simpler:\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;!-- New approach with defineModel --&gt;\r\n&lt;template&gt;\r\n  &lt;input type=\"text\" v-model=\"modelValue\" /&gt;\r\n&lt;/template&gt;\r\n\r\n&lt;script setup&gt;\r\nconst modelValue = defineModel();\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch2 id=\"key-features-and-usage\">Key Features and Usage\u003C/h2>\r\n\u003Ch3 id=\"basic-implementation\">Basic Implementation\u003C/h3>\r\n\u003Cp>The macro automatically declares a \u003Ccode>modelValue\u003C/code> prop and corresponding\u003Ccode> update:modelValue \u003C/code>event:\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>// Basic usage\r\nconst model = defineModel()\r\n\r\n// With type constraints\r\nconst model = defineModel({ type: String })\r\n\r\n// Named models for multiple v-model bindings\r\nconst count = defineModel('count', { type: Number, default: 0 })\u003C/code>\u003C/pre>\r\n\u003Ch3 id=\"advanced-features\">Advanced Features\u003C/h3>\r\n\u003Cp>defineModel takes care of both date synchronization and event emission behind the scenes, eliminating the need for manual event handling and keeping your code concise.\u003C/p>\r\n\u003Cp>\u003Cstrong>Modifiers Support:\u003C/strong>\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>const [modelValue, modelModifiers] = defineModel({\r\n  set(value) {\r\n    if (modelModifiers.trim) {\r\n      return value.trim()\r\n    }\r\n    return value\r\n  }\r\n})\u003C/code>\u003C/pre>\r\n\u003Cp class=\"whitespace-normal break-words\">\u003Cstrong>TypeScript Integration:\u003C/strong>\u003C/p>\r\n\u003Cdiv class=\"relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg\">\r\n\u003Cdiv class=\"sticky opacity-0 group-hover/copy:opacity-100 top-2 py-2 h-12 w-0 float-right\">\r\n\u003Cdiv class=\"absolute right-0 h-8 px-2 items-center inline-flex\">\r\n\u003Cdiv class=\"relative\">\r\n\u003Cdiv class=\"flex items-center justify-center transition-all opacity-100 scale-100\">\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>const modelValue = defineModel&lt;string&gt;({ required: true })\r\nconst [modelValue, modifiers] = defineModel&lt;string, 'trim' | 'uppercase'&gt;()\u003C/code>\u003C/pre>\r\n\u003C/div>\r\n\u003Cdiv class=\"flex items-center justify-center absolute top-0 left-0 transition-all opacity-0 scale-50\">&nbsp;\u003C/div>\r\n\u003C/div>\r\n\u003C/div>\r\n\u003C/div>\r\n\u003C/div>\r\n\u003Ch2 id=\"important-considerations\">Important Considerations\u003C/h2>\r\n\u003Cp>\u003Cstrong>Synchronization Warning:\u003C/strong> &nbsp;&nbsp;Be careful with default values. If a child component has a default value but the parent doesn't provide one, it can cause desynchronization between components.\u003Cbr />\u003Cstrong>Compile-Time Nature: &nbsp;\u003C/strong>defineModel is \"just\" another macro that is compiled into an \"old\" component defining method via defineComponent, meaning it's transformed at build time into traditional prop and emit declarations.\u003C/p>\r\n\u003Ch2 id=\"when-to-use-definemodel\">When to Use defineModel()\u003C/h2>\r\n\u003Cul>\r\n\u003Cli>Creating reusable form components\u003C/li>\r\n\u003Cli>Building complex input components with validation\u003C/li>\r\n\u003Cli>Implementing components that need bi-directional data flow\u003C/li>\r\n\u003Cli>Working with multiple \u003Ccode>v-model\u003C/code> binding on a single component\u003C/li>\r\n\u003C/ul>\r\n\u003Ch2 id=\"conclusion\">Conclusion\u003C/h2>\r\n\u003Cp class=\"whitespace-normal break-words\">\u003Ccode class=\"bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">defineModel()\u003C/code> represents Vue's commitment to developer experience, offering a more intuitive and maintainable approach to two-way binding. While v-model remains useful for basic scenarios, defineModel offers a cleaner and more concise approach for complex data structures in custom components. As Vue applications grow in complexity, this macro becomes an essential tool for efficient component communication.\u003C/p>\r\n\u003Cp class=\"whitespace-normal break-words\">The introduction of \u003Ccode class=\"bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]\">defineModel()\u003C/code> in Vue 3.4+ showcases the framework's evolution toward more declarative and less verbose component development, making two-way binding both more powerful and easier to implement.\u003C/p>\r\n\u003Cp class=\"whitespace-normal break-words\">&nbsp;\u003C/p>\r\n\u003Cp class=\"whitespace-normal break-words\">For Details and official guide, you can explore \u003Ca href=\"https://vuejs.org/guide/components/v-model\">https://vuejs.org/guide/components/v-model\u003C/a> this.\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Cp style=\"text-align: center;\">\u003Cstrong>Happy Coding !!!\u003C/strong>\u003C/p>","2025-09-13T06:29:00.000000Z","2025-09-13T07:05:43.000000Z","https://admin.ssbhattarai.com.np/storage/articles/banners/0CMdqJvbOR4fgzFyk6OPR531IOT4krRZUQV6tPxq.png",[67,70,73,76,79,82,85,88],{"level":19,"text":68,"id":69},"What is defineModel()?","what-is-definemodel",{"level":19,"text":71,"id":72},"The Problem It Solves","the-problem-it-solves",{"level":19,"text":74,"id":75},"Key Features and Usage","key-features-and-usage",{"level":16,"text":77,"id":78},"Basic Implementation","basic-implementation",{"level":16,"text":80,"id":81},"Advanced Features","advanced-features",{"level":19,"text":83,"id":84},"Important Considerations","important-considerations",{"level":19,"text":86,"id":87},"When to Use defineModel()","when-to-use-definemodel",{"level":19,"text":89,"id":90},"Conclusion","conclusion",[],{"id":93,"name":94,"slug":95},1,"Frontend","frontend",[97,98,100,103],{"name":94,"slug":95},{"name":99,"slug":99},"javascript",{"name":101,"slug":102},"web development","web-development",{"name":104,"slug":104},"vue3",{"title":106,"slug":107,"excerpt":108,"content":109,"author":9,"author_bio":15,"published_at":110,"updated_at":111,"is_featured":14,"is_external":14,"banner_image":112,"reading_time":113,"toc":114,"official_docs":152,"category":153,"tags":154,"meta":15},"Using defineExpose script: A hidden gem in Vue 3","using-defineexpose-script-a-hidden-gem-in-vue-3","Explore Vue 3’s defineExpose macro to safely expose child methods and properties. Learn patterns, best practices, and real examples.","\u003Ch2 id=\"introduction\">Introduction\u003C/h2>\r\n\u003Cp>Vue 3 introduced several composition API features that change how we build components, and among these powerful additions lies a lesser-known gem: \u003Ccode>defineExpose\u003C/code>. This compiler macro provides a clean and more effective way to expose specific methods and properties from child components to their parents, offering developers greater control over component interfaces.\u003C/p>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch2 id=\"what-is-defineexpose\">What is defineExpose()?\u003C/h2>\r\n\u003Cp>defineExpose is a compile-time macro available in Vue 3's \u003Ccode>&lt;script setup&gt;\u003C/code> syntax that allows you to explicitly define which properties and methods should be accessible to parent components through template refs. Unlike the Options API, where all methods and data are automatically exposed, the Composition API&nbsp; \u003Ccode>&lt;script setup&gt;\u003C/code> keeps everything private by default; that's where defineExpose becomes invaluable.\u003C/p>\r\n\u003Ch2 id=\"the-problem-defineexpose-solves\">The problem defineExpose solves?\u003C/h2>\r\n\u003Cp>In traditional Vue 2 or options API components, parent components could access any method or property of child components through refs. However, with the composition API, this automatic exposure is disabled for better encapsulation. Sometimes you need to break this encapsulation intentionally, and that's exactly what \u003Ccode>defineExpose\u003C/code> enables. For understanding the options API way, see the example below.\u003C/p>\r\n\u003Ch3 id=\"options-api-example\">Options API example:\u003C/h3>\r\n\u003Cp>\u003Cstrong>Child.vue\u003C/strong>\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;template&gt;\r\n  &lt;p&gt;Count: {{ count }}&lt;/p&gt;\r\n&lt;/template&gt;\r\n\r\n&lt;script&gt;\r\nexport default {\r\n  data() {\r\n    return { count: 0 }\r\n  },\r\n  methods: {\r\n    increment() {\r\n      this.count++\r\n    }\r\n  }\r\n}\r\n&lt;/script&gt;\r\n\u003C/code>\u003C/pre>\r\n\u003Cp>\u003Cstrong>Parent.vue\u003C/strong>\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;template&gt;\r\n  &lt;Child ref=\"child\" /&gt;\r\n  &lt;button @click=\"callChild\"&gt;Increment From Parent&lt;/button&gt;\r\n&lt;/template&gt;\r\n\r\n&lt;script&gt;\r\nimport Child from './Child.vue'\r\n\r\nexport default {\r\n  components: { Child },\r\n  methods: {\r\n    callChild() {\r\n      // can directly access any data or method\r\n      this.$refs.child.increment()\r\n      console.log(this.$refs.child.count)\r\n    }\r\n  }\r\n}\r\n&lt;/script&gt;\r\n\u003C/code>\u003C/pre>\r\n\u003Cp>In this, the parent can call\u003Ccode> increment ()\u003C/code> or even read \u003Ccode>count\u003C/code> without the child exposing it.\u003C/p>\r\n\u003Ch2 id=\"basic-implementation-of-defineexpose\">Basic Implementation of \u003Ccode>defineExpose()\u003C/code>\u003C/h2>\r\n\u003Cp>Here's a simple example demonstrating how to use&nbsp;\u003C/p>\r\n\u003Cp>\u003Cstrong>Child component (childComponent.vue):\u003C/strong>\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;script setup&gt;\r\nimport { ref } from 'vue'\r\n\r\nconst count = ref(0)\r\nconst message = ref('Hello from child!')\r\n\r\nconst increment = () =&gt; {\r\n  count.value++\r\n}\r\n\r\nconst reset = () =&gt; {\r\n  count.value = 0\r\n}\r\n\r\nconst updateMessage = (newMessage) =&gt; {\r\n  message.value = newMessage\r\n}\r\n\r\n// Expose specific methods and properties\r\ndefineExpose({\r\n  count,\r\n  increment,\r\n  reset,\r\n  updateMessage\r\n})\r\n&lt;/script&gt;\r\n\r\n&lt;template&gt;\r\n  &lt;div&gt;\r\n    &lt;p&gt;Count: {{ count }}&lt;/p&gt;\r\n    &lt;p&gt;{{ message }}&lt;/p&gt;\r\n    &lt;button @click=\"increment\"&gt;Increment&lt;/button&gt;\r\n    &lt;button @click=\"reset\"&gt;Reset&lt;/button&gt;\r\n  &lt;/div&gt;\r\n&lt;/template&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>\u003Cstrong>Parent component (ParentComponent.vue):\u003C/strong>\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;script setup&gt;\r\nimport { ref } from 'vue'\r\nimport ChildComponent from './ChildComponent.vue'\r\n\r\nconst childRef = ref()\r\n\r\nconst handleParentIncrement = () =&gt; {\r\n  childRef.value.increment()\r\n}\r\n\r\nconst handleReset = () =&gt; {\r\n  childRef.value.reset()\r\n}\r\n\r\nconst changeChildMessage = () =&gt; {\r\n  childRef.value.updateMessage('Updated from parent!')\r\n}\r\n&lt;/script&gt;\r\n\r\n&lt;template&gt;\r\n  &lt;div&gt;\r\n    &lt;h2&gt;Parent Component&lt;/h2&gt;\r\n    &lt;button @click=\"handleParentIncrement\"&gt;Increment from Parent&lt;/button&gt;\r\n    &lt;button @click=\"handleReset\"&gt;Reset from Parent&lt;/button&gt;\r\n    &lt;button @click=\"changeChildMessage\"&gt;Change Message&lt;/button&gt;\r\n    \r\n    &lt;ChildComponent ref=\"childRef\" /&gt;\r\n  &lt;/div&gt;\r\n&lt;/template&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch2 id=\"practical-use-cases\">Practical Use Cases\u003C/h2>\r\n\u003Ch3 id=\"form-validation\">Form Validation\u003C/h3>\r\n\u003Cp>One of the most common use cases for \u003Ccode>defineExpose\u003C/code> is creating reusable form components that can be validated from the parent components:\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;!-- FormInput.vue --&gt;\r\n&lt;script setup&gt;\r\nimport { ref, computed } from 'vue'\r\n\r\nconst props = defineProps(['modelValue', 'rules'])\r\nconst emit = defineEmits(['update:modelValue'])\r\n\r\nconst inputValue = computed({\r\n  get: () =&gt; props.modelValue,\r\n  set: (value) =&gt; emit('update:modelValue', value)\r\n})\r\n\r\nconst errors = ref([])\r\n\r\nconst validate = () =&gt; {\r\n  errors.value = []\r\n  if (props.rules) {\r\n    props.rules.forEach(rule =&gt; {\r\n      const result = rule(inputValue.value)\r\n      if (result !== true) {\r\n        errors.value.push(result)\r\n      }\r\n    })\r\n  }\r\n  return errors.value.length === 0\r\n}\r\n\r\nconst clearErrors = () =&gt; {\r\n  errors.value = []\r\n}\r\n\r\ndefineExpose({\r\n  validate,\r\n  clearErrors,\r\n  hasErrors: computed(() =&gt; errors.value.length &gt; 0)\r\n})\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch3 id=\"modal-components\">Modal Components\u003C/h3>\r\n\u003Cp>Another excellent use case is modal components, where the parent needs to control the modal's visibility.\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;!-- Modal.vue --&gt;\r\n&lt;script setup&gt;\r\nimport { ref } from 'vue'\r\n\r\nconst isVisible = ref(false)\r\n\r\nconst show = () =&gt; {\r\n  isVisible.value = true\r\n}\r\n\r\nconst hide = () =&gt; {\r\n  isVisible.value = false\r\n}\r\n\r\nconst toggle = () =&gt; {\r\n  isVisible.value = !isVisible.value\r\n}\r\n\r\ndefineExpose({\r\n  show,\r\n  hide,\r\n  toggle,\r\n  isVisible: readonly(isVisible)\r\n})\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003Cp>&nbsp;\u003C/p>\r\n\u003Ch2 id=\"best-practices\">Best Practices\u003C/h2>\r\n\u003Col>\r\n\u003Cli>\u003Cstrong>Be selective:\u003C/strong> \u003Cbr />Only expose what's necessary. The principle of least privilege applies here - expose only the methods and properties that parent components genuinely need to access.\u003C/li>\r\n\u003Cli>\u003Cstrong>Use Descriptive Names:\u003C/strong> \u003Cbr />Choose clear, descriptive names for exposed methods that clearly indicate their purpose and expected behavior.\u003C/li>\r\n\u003Cli>\u003Cstrong>Consider readonly for state: \u003C/strong>\u003Cbr />When exposing state, consider using \u003Ccode>readonly()\u003C/code> to prevent parent components from directly mutating the state\u003Cbr />\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;script setup&gt;\r\nimport { ref, readonly } from 'vue'\r\n\r\nconst internalState = ref('some value')\r\n\r\ndefineExpose({\r\n  state: readonly(internalState),\r\n  updateState: (newValue) =&gt; {\r\n    internalState.value = newValue\r\n  }\r\n})\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003C/li>\r\n\u003C/ol>\r\n\u003Ch2 id=\"alternative-approaches\">Alternative Approaches\u003C/h2>\r\n\u003Cp>While defineExpose is powerful, consider whether it's the right solution. Sometimes, proper event emission or props passing might be more appropriate.\u003C/p>\r\n\u003Cul>\r\n\u003Cli>\u003Cstrong>Events\u003C/strong>: For communicating state changes upward\u003C/li>\r\n\u003Cli>\u003Cstrong>Props\u003C/strong>: For passing data downward\u003C/li>\r\n\u003Cli>\u003Cstrong>Provide/Inject\u003C/strong>: For deep component tree communication\u003C/li>\r\n\u003Cli>S\u003Cstrong>tate management:\u003C/strong> for complex application state\u003C/li>\r\n\u003C/ul>\r\n\u003Ch2 id=\"typescript-support\">TypeScript Support\u003C/h2>\r\n\u003Cp>\u003Ccode>defineExpose\u003C/code> works seamlessly with TypeScript; you can define interfaces for better type safety:\u003C/p>\r\n\u003Cpre class=\"language-javascript\">\u003Ccode>&lt;script setup lang=\"ts\"&gt;\r\ninterface ExposedAPI {\r\n  validate: () =&gt; boolean\r\n  reset: () =&gt; void\r\n  value: string\r\n}\r\n\r\nconst validate = (): boolean =&gt; {\r\n  // validation logic\r\n  return true\r\n}\r\n\r\nconst reset = (): void =&gt; {\r\n  // reset logic\r\n}\r\n\r\nconst value = ref('')\r\n\r\ndefineExpose&lt;ExposedAPI&gt;({\r\n  validate,\r\n  reset,\r\n  value\r\n})\r\n&lt;/script&gt;\u003C/code>\u003C/pre>\r\n\u003Ch2 id=\"nbsp\">&nbsp;\u003C/h2>\r\n\u003Ch2 id=\"conclusion\">Conclusion\u003C/h2>\r\n\u003Cp>\u003Ccode>defineExpose\u003C/code> is a valuable addition to the Vue 3 toolkit that strikes a balance between component encapsulation and necessary parent-child communication. Remember that with great power comes great responsibility &ndash; use defineExpose thoughtfully to maintain clean component architecture while solving real communication challenges in your Vue 3 applications.\u003C/p>\r\n\u003Cp>The key is understanding when to use it versus other communication patterns, ensuring your components remain maintainable and your application architecture stays clean and predictable.\u003C/p>","2025-09-05T21:37:00.000000Z","2025-09-06T15:56:15.000000Z","https://admin.ssbhattarai.com.np/storage/articles/banners/kQp61jrdiwIoto9mgErUBr5PgCpEqhqtlA6CZPWr.png",5,[115,118,121,124,127,130,133,136,139,142,145,148,151],{"level":19,"text":116,"id":117},"Introduction","introduction",{"level":19,"text":119,"id":120},"What is defineExpose()?","what-is-defineexpose",{"level":19,"text":122,"id":123},"The problem defineExpose solves?","the-problem-defineexpose-solves",{"level":16,"text":125,"id":126},"Options API example:","options-api-example",{"level":19,"text":128,"id":129},"Basic Implementation of defineExpose()","basic-implementation-of-defineexpose",{"level":19,"text":131,"id":132},"Practical Use Cases","practical-use-cases",{"level":16,"text":134,"id":135},"Form Validation","form-validation",{"level":16,"text":137,"id":138},"Modal Components","modal-components",{"level":19,"text":140,"id":141},"Best Practices","best-practices",{"level":19,"text":143,"id":144},"Alternative Approaches","alternative-approaches",{"level":19,"text":146,"id":147},"TypeScript Support","typescript-support",{"level":19,"text":149,"id":150},"&nbsp;","nbsp",{"level":19,"text":89,"id":90},[],{"id":93,"name":94,"slug":95},[155,158,159],{"name":156,"slug":157},"Vue","vue",{"name":94,"slug":95},{"name":101,"slug":102}]