[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"header-categories":3,"post-design-system-component-library-vue-tailwind":73,"parsed-post-f8c52ae7-6edb-475d-b596-8ca9fe8a65d2":152},{"success":4,"data":5},true,{"items":6,"pagination":70},[7,16,24,32,40,48,56,63],{"id":8,"name":9,"description":10,"parentId":11,"createdAt":12,"updatedAt":12,"parent":11,"children":13,"_count":14},"ai-future","AI & The Future","Artificial intelligence and emerging technology",null,"2026-07-24T06:02:45.990Z",[],{"posts":15},1,{"id":17,"name":18,"description":19,"parentId":11,"createdAt":20,"updatedAt":20,"parent":11,"children":21,"_count":22},"tools-productivity","Tools & Productivity","Developer tools and workflow optimization","2026-07-24T06:02:45.712Z",[],{"posts":23},7,{"id":25,"name":26,"description":27,"parentId":11,"createdAt":28,"updatedAt":28,"parent":11,"children":29,"_count":30},"career","Career & Growth","Professional development for developers","2026-07-24T06:02:45.486Z",[],{"posts":31},3,{"id":33,"name":34,"description":35,"parentId":11,"createdAt":36,"updatedAt":36,"parent":11,"children":37,"_count":38},"opinion","Opinion & Analysis","Industry analysis and technical opinions","2026-07-24T06:02:45.272Z",[],{"posts":39},6,{"id":41,"name":42,"description":43,"parentId":11,"createdAt":44,"updatedAt":44,"parent":11,"children":45,"_count":46},"tutorials","Tutorials","Step-by-step learning guides","2026-07-24T06:02:44.965Z",[],{"posts":47},21,{"id":49,"name":50,"description":51,"parentId":11,"createdAt":52,"updatedAt":52,"parent":11,"children":53,"_count":54},"software-engineering","Software Engineering","Best practices, patterns, and principles","2026-07-24T06:02:44.689Z",[],{"posts":55},24,{"id":57,"name":58,"description":59,"parentId":11,"createdAt":60,"updatedAt":60,"parent":11,"children":61,"_count":62},"devops-cloud","DevOps & Cloud","Infrastructure, deployment, and cloud computing","2026-07-24T06:02:44.453Z",[],{"posts":39},{"id":64,"name":65,"description":66,"parentId":11,"createdAt":67,"updatedAt":67,"parent":11,"children":68,"_count":69},"web-development","Web Development","Frontend and backend web development tutorials and guides","2026-07-24T06:02:44.169Z",[],{"posts":55},{"page":15,"limit":71,"total":71,"totalPages":15,"hasNext":72,"hasPrev":72},8,false,{"success":4,"data":74},{"id":75,"slug":76,"title":77,"excerpt":78,"content":79,"status":80,"visibility":81,"featuredImage":82,"canonicalUrl":11,"readingTime":83,"viewCount":84,"commentEnabled":4,"publishedAt":85,"scheduledAt":11,"createdAt":86,"updatedAt":87,"seoTitle":88,"seoDescription":78,"seoKeywords":11,"authorId":89,"author":90,"coAuthors":95,"tags":96,"categories":117,"comments":120,"_count":121,"relatedPosts":123},"f8c52ae7-6edb-475d-b596-8ca9fe8a65d2","design-system-component-library-vue-tailwind","Building a Design System Component Library with Vue and Tailwind","Create a reusable, themeable component library using Vue 3, Tailwind CSS, and proper documentation with Storybook.","## Why Build Your Own?\n\nReady-made libraries are great for prototyping. But for production products, a custom design system gives you:\n\n- Exact match to your brand\n- Only the components you need (smaller bundle)\n- Full control over behavior and accessibility\n- Consistent patterns across all products\n\n## Project Structure\n\n```\ndesign-system\u002F\n├── src\u002F\n│   ├── components\u002F\n│   │   ├── Button\u002F\n│   │   │   ├── Button.vue\n│   │   │   ├── Button.test.ts\n│   │   │   ├── Button.stories.ts\n│   │   │   └── index.ts\n│   │   ├── Input\u002F\n│   │   └── Modal\u002F\n│   ├── composables\u002F\n│   ├── tokens\u002F\n│   │   └── colors.ts\n│   └── index.ts          ← Public API\n├── tailwind.config.ts\n└── package.json\n```\n\n## The Button Component\n\n```vue\n\u003C!-- components\u002FButton\u002FButton.vue -->\n\u003Ctemplate>\n  \u003Ccomponent\n    :is=\"tag\"\n    :class=\"buttonClasses\"\n    :disabled=\"disabled || loading\"\n    v-bind=\"$attrs\"\n  >\n    \u003Cspan v-if=\"loading\" class=\"animate-spin mr-2\">\n      \u003CIconLoader class=\"w-4 h-4\" \u002F>\n    \u003C\u002Fspan>\n    \u003Cspan v-if=\"$slots.leading\" class=\"mr-2\">\n      \u003Cslot name=\"leading\" \u002F>\n    \u003C\u002Fspan>\n    \u003Cslot \u002F>\n    \u003Cspan v-if=\"$slots.trailing\" class=\"ml-2\">\n      \u003Cslot name=\"trailing\" \u002F>\n    \u003C\u002Fspan>\n  \u003C\u002Fcomponent>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nexport interface ButtonProps {\n  variant?: 'primary' | 'secondary' | 'ghost' | 'danger'\n  size?: 'xs' | 'sm' | 'md' | 'lg'\n  loading?: boolean\n  disabled?: boolean\n  tag?: string | Component\n}\n\nconst props = withDefaults(defineProps\u003CButtonProps>(), {\n  variant: 'primary',\n  size: 'md',\n  tag: 'button',\n})\n\nconst buttonClasses = computed(() => [\n  'inline-flex items-center justify-center font-medium rounded-lg',\n  'transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-offset-2',\n  'disabled:opacity-50 disabled:cursor-not-allowed',\n  variantClasses[props.variant],\n  sizeClasses[props.size],\n])\n\nconst variantClasses = {\n  primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500',\n  secondary: 'border border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500',\n  ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',\n  danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',\n}\n\nconst sizeClasses = {\n  xs: 'px-2 py-1 text-xs',\n  sm: 'px-3 py-1.5 text-sm',\n  md: 'px-4 py-2 text-sm',\n  lg: 'px-5 py-2.5 text-base',\n}\n\u003C\u002Fscript>\n```\n\n## Token-Based Theming\n\n```typescript\n\u002F\u002F tokens\u002Fcolors.ts\nexport const colors = {\n  primary: {\n    50: 'var(--color-primary-50, #eff6ff)',\n    500: 'var(--color-primary-500, #3b82f6)',\n    600: 'var(--color-primary-600, #2563eb)',\n    700: 'var(--color-primary-700, #1d4ed8)',\n  },\n}\n```\n\n::callout{icon=\"i-lucide-palette\" color=\"primary\"}\nCSS custom properties as the theming layer means consumers can override your design tokens without rebuilding the library. Just set `--color-primary-500` to their brand color.\n::\n\n## Publishing as a Package\n\n```json\n{\n  \"name\": \"@myorg\u002Fdesign-system\",\n  \"exports\": {\n    \".\": \".\u002Fsrc\u002Findex.ts\",\n    \".\u002Ftailwind\": \".\u002Ftailwind.config.ts\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.4.0\",\n    \"tailwindcss\": \"^4.0.0\"\n  }\n}\n```\n\nConsumer usage:\n\n```typescript\n\u002F\u002F Consumer's tailwind.config.ts\nimport designSystem from '@myorg\u002Fdesign-system\u002Ftailwind'\n\nexport default {\n  presets: [designSystem],\n}\n```\n\n```vue\n\u003Cscript setup>\nimport { Button, Input, Modal } from '@myorg\u002Fdesign-system'\n\u003C\u002Fscript>\n```\n\n## Documentation Is Critical\n\nWithout docs, nobody will use your design system. At minimum:\n- Props table for each component\n- Visual examples of all variants\n- Copy-pasteable code snippets\n- Accessibility notes\n\nA design system is a product. Treat it like one.\n","published","public","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1633356122544-f134324a6cee?w=1200&q=80",10,215,"2026-05-02T06:04:23.990Z","2026-07-24T06:04:23.992Z","2026-07-28T13:21:44.400Z","Building a Design System Component Library with Vue and Tailwind | BitBlog","fddb5d93-7a2c-4d86-a06a-fa32e73a01c6",{"email":91,"bio":92,"id":89,"name":93,"avatarUrl":94},"mbeahessilfieprince@gmail.com","Fullstack Software Developer ","Mbeah Essilfie","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F93322394?v=4",[],[97,102,107,112],{"id":98,"name":99,"color":100,"description":101},"typescript","TypeScript","#3178c6","Typed superset of JavaScript",{"id":103,"name":104,"color":105,"description":106},"vue","Vue","#4fc08d","The Progressive JavaScript Framework",{"id":108,"name":109,"color":110,"description":111},"css","CSS","#1572b6","Cascading Style Sheets",{"id":113,"name":114,"color":115,"description":116},"tailwind","Tailwind CSS","#06b6d4","Utility-first CSS framework",[118,119],{"id":64,"name":65,"description":66},{"id":41,"name":42,"description":43},[],{"comments":122},0,[124,133,142],{"id":125,"slug":126,"title":127,"excerpt":128,"featuredImage":129,"viewCount":130,"readingTime":71,"publishedAt":131,"author":132},"2997028f-4d22-4eb7-9d86-894a54cb559a","building-type-safe-apis-nuxt3-prisma","Building Type-Safe APIs with Nuxt 3 and Prisma","Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1498050108023-c5249f4df085?w=1200&q=80",1922,"2026-07-23T06:02:46.910Z",{"id":89,"name":93,"avatarUrl":94},{"id":134,"slug":135,"title":136,"excerpt":137,"featuredImage":138,"viewCount":139,"readingTime":83,"publishedAt":140,"author":141},"da9e4553-8b0d-411e-b4ec-f9684017e163","mastering-tailwind-css-design-systems","Mastering Tailwind CSS: From Utility Classes to Design Systems","Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1555066931-4365d14bab8c?w=1200&q=80",257,"2026-07-21T06:02:49.268Z",{"id":89,"name":93,"avatarUrl":94},{"id":143,"slug":144,"title":145,"excerpt":146,"featuredImage":147,"viewCount":148,"readingTime":149,"publishedAt":150,"author":151},"50add5fc-4026-4267-b917-7f71ea9e35b0","complete-guide-vue3-composables","The Complete Guide to Vue 3 Composables","Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1517694712202-14dd9538aa97?w=1200&q=80",990,12,"2026-07-19T06:02:51.753Z",{"id":89,"name":93,"avatarUrl":94},{"data":153,"body":155,"toc":347},{"title":154,"description":154},"",{"type":156,"children":157},"root",[158,167,173,198,204,216,222,232,238,247,266,272,282,287,295,303,309,314,337,342],{"type":159,"tag":160,"props":161,"children":163},"element","h2",{"id":162},"why-build-your-own",[164],{"type":165,"value":166},"text","Why Build Your Own?",{"type":159,"tag":168,"props":169,"children":170},"p",{},[171],{"type":165,"value":172},"Ready-made libraries are great for prototyping. But for production products, a custom design system gives you:",{"type":159,"tag":174,"props":175,"children":176},"ul",{},[177,183,188,193],{"type":159,"tag":178,"props":179,"children":180},"li",{},[181],{"type":165,"value":182},"Exact match to your brand",{"type":159,"tag":178,"props":184,"children":185},{},[186],{"type":165,"value":187},"Only the components you need (smaller bundle)",{"type":159,"tag":178,"props":189,"children":190},{},[191],{"type":165,"value":192},"Full control over behavior and accessibility",{"type":159,"tag":178,"props":194,"children":195},{},[196],{"type":165,"value":197},"Consistent patterns across all products",{"type":159,"tag":160,"props":199,"children":201},{"id":200},"project-structure",[202],{"type":165,"value":203},"Project Structure",{"type":159,"tag":205,"props":206,"children":210},"pre",{"className":207,"code":209,"language":165},[208],"language-text","design-system\u002F\n├── src\u002F\n│   ├── components\u002F\n│   │   ├── Button\u002F\n│   │   │   ├── Button.vue\n│   │   │   ├── Button.test.ts\n│   │   │   ├── Button.stories.ts\n│   │   │   └── index.ts\n│   │   ├── Input\u002F\n│   │   └── Modal\u002F\n│   ├── composables\u002F\n│   ├── tokens\u002F\n│   │   └── colors.ts\n│   └── index.ts          ← Public API\n├── tailwind.config.ts\n└── package.json\n",[211],{"type":159,"tag":212,"props":213,"children":214},"code",{"__ignoreMap":154},[215],{"type":165,"value":209},{"type":159,"tag":160,"props":217,"children":219},{"id":218},"the-button-component",[220],{"type":165,"value":221},"The Button Component",{"type":159,"tag":205,"props":223,"children":227},{"className":224,"code":225,"language":103,"meta":154,"style":226},"language-vue","\u003C!-- components\u002FButton\u002FButton.vue -->\n\u003Ctemplate>\n  \u003Ccomponent\n    :is=\"tag\"\n    :class=\"buttonClasses\"\n    :disabled=\"disabled || loading\"\n    v-bind=\"$attrs\"\n  >\n    \u003Cspan v-if=\"loading\" class=\"animate-spin mr-2\">\n      \u003CIconLoader class=\"w-4 h-4\" \u002F>\n    \u003C\u002Fspan>\n    \u003Cspan v-if=\"$slots.leading\" class=\"mr-2\">\n      \u003Cslot name=\"leading\" \u002F>\n    \u003C\u002Fspan>\n    \u003Cslot \u002F>\n    \u003Cspan v-if=\"$slots.trailing\" class=\"ml-2\">\n      \u003Cslot name=\"trailing\" \u002F>\n    \u003C\u002Fspan>\n  \u003C\u002Fcomponent>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nexport interface ButtonProps {\n  variant?: 'primary' | 'secondary' | 'ghost' | 'danger'\n  size?: 'xs' | 'sm' | 'md' | 'lg'\n  loading?: boolean\n  disabled?: boolean\n  tag?: string | Component\n}\n\nconst props = withDefaults(defineProps\u003CButtonProps>(), {\n  variant: 'primary',\n  size: 'md',\n  tag: 'button',\n})\n\nconst buttonClasses = computed(() => [\n  'inline-flex items-center justify-center font-medium rounded-lg',\n  'transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-offset-2',\n  'disabled:opacity-50 disabled:cursor-not-allowed',\n  variantClasses[props.variant],\n  sizeClasses[props.size],\n])\n\nconst variantClasses = {\n  primary: 'bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500',\n  secondary: 'border border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500',\n  ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',\n  danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',\n}\n\nconst sizeClasses = {\n  xs: 'px-2 py-1 text-xs',\n  sm: 'px-3 py-1.5 text-sm',\n  md: 'px-4 py-2 text-sm',\n  lg: 'px-5 py-2.5 text-base',\n}\n\u003C\u002Fscript>\n","undefined",[228],{"type":159,"tag":212,"props":229,"children":230},{"__ignoreMap":154},[231],{"type":165,"value":225},{"type":159,"tag":160,"props":233,"children":235},{"id":234},"token-based-theming",[236],{"type":165,"value":237},"Token-Based Theming",{"type":159,"tag":205,"props":239,"children":242},{"className":240,"code":241,"language":98,"meta":154,"style":226},"language-typescript","\u002F\u002F tokens\u002Fcolors.ts\nexport const colors = {\n  primary: {\n    50: 'var(--color-primary-50, #eff6ff)',\n    500: 'var(--color-primary-500, #3b82f6)',\n    600: 'var(--color-primary-600, #2563eb)',\n    700: 'var(--color-primary-700, #1d4ed8)',\n  },\n}\n",[243],{"type":159,"tag":212,"props":244,"children":245},{"__ignoreMap":154},[246],{"type":165,"value":241},{"type":159,"tag":248,"props":249,"children":252},"callout",{"color":250,"icon":251},"primary","i-lucide-palette",[253],{"type":159,"tag":168,"props":254,"children":255},{},[256,258,264],{"type":165,"value":257},"CSS custom properties as the theming layer means consumers can override your design tokens without rebuilding the library. Just set ",{"type":159,"tag":212,"props":259,"children":261},{"className":260},[],[262],{"type":165,"value":263},"--color-primary-500",{"type":165,"value":265}," to their brand color.",{"type":159,"tag":160,"props":267,"children":269},{"id":268},"publishing-as-a-package",[270],{"type":165,"value":271},"Publishing as a Package",{"type":159,"tag":205,"props":273,"children":277},{"className":274,"code":275,"language":276,"meta":154,"style":226},"language-json","{\n  \"name\": \"@myorg\u002Fdesign-system\",\n  \"exports\": {\n    \".\": \".\u002Fsrc\u002Findex.ts\",\n    \".\u002Ftailwind\": \".\u002Ftailwind.config.ts\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.4.0\",\n    \"tailwindcss\": \"^4.0.0\"\n  }\n}\n","json",[278],{"type":159,"tag":212,"props":279,"children":280},{"__ignoreMap":154},[281],{"type":165,"value":275},{"type":159,"tag":168,"props":283,"children":284},{},[285],{"type":165,"value":286},"Consumer usage:",{"type":159,"tag":205,"props":288,"children":290},{"className":240,"code":289,"language":98,"meta":154,"style":226},"\u002F\u002F Consumer's tailwind.config.ts\nimport designSystem from '@myorg\u002Fdesign-system\u002Ftailwind'\n\nexport default {\n  presets: [designSystem],\n}\n",[291],{"type":159,"tag":212,"props":292,"children":293},{"__ignoreMap":154},[294],{"type":165,"value":289},{"type":159,"tag":205,"props":296,"children":298},{"className":224,"code":297,"language":103,"meta":154,"style":226},"\u003Cscript setup>\nimport { Button, Input, Modal } from '@myorg\u002Fdesign-system'\n\u003C\u002Fscript>\n",[299],{"type":159,"tag":212,"props":300,"children":301},{"__ignoreMap":154},[302],{"type":165,"value":297},{"type":159,"tag":160,"props":304,"children":306},{"id":305},"documentation-is-critical",[307],{"type":165,"value":308},"Documentation Is Critical",{"type":159,"tag":168,"props":310,"children":311},{},[312],{"type":165,"value":313},"Without docs, nobody will use your design system. At minimum:",{"type":159,"tag":174,"props":315,"children":316},{},[317,322,327,332],{"type":159,"tag":178,"props":318,"children":319},{},[320],{"type":165,"value":321},"Props table for each component",{"type":159,"tag":178,"props":323,"children":324},{},[325],{"type":165,"value":326},"Visual examples of all variants",{"type":159,"tag":178,"props":328,"children":329},{},[330],{"type":165,"value":331},"Copy-pasteable code snippets",{"type":159,"tag":178,"props":333,"children":334},{},[335],{"type":165,"value":336},"Accessibility notes",{"type":159,"tag":168,"props":338,"children":339},{},[340],{"type":165,"value":341},"A design system is a product. Treat it like one.",{"type":159,"tag":343,"props":344,"children":345},"style",{},[346],{"type":165,"value":154},{"title":154,"searchDepth":348,"depth":348,"links":349},2,[350,351,352,353,354,355],{"id":162,"depth":348,"text":166},{"id":200,"depth":348,"text":203},{"id":218,"depth":348,"text":221},{"id":234,"depth":348,"text":237},{"id":268,"depth":348,"text":271},{"id":305,"depth":348,"text":308}]