[{"data":1,"prerenderedAt":1813},["ShallowReactive",2],{"blog-lit-web-components-astro-docs":3,"blog-post-nav":1775},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"body":11,"_type":1769,"_id":1770,"_source":1771,"_file":1772,"_stem":1773,"_extension":1774},"/blog/lit-web-components-astro-docs","blog",false,"","Building a framework-free web component library with Lit and Astro","How I built a small library of standalone custom elements with Lit, a single-source registry, and an auto-generated Astro docs site.","2026-03-10",{"type":12,"children":13,"toc":1763},"root",[14,39,58,65,86,659,712,718,731,1246,1266,1272,1293,1507,1519,1563,1583,1679,1684,1690,1752,1757],{"type":15,"tag":16,"props":17,"children":18},"element","p",{},[19,22,28,30,37],{"type":20,"value":21},"text","I keep reaching for the same handful of UI primitives (a button, a toggle, a counter) across projects that use wildly different stacks. Some are Nuxt, some are plain HTML, one is an Astro site, one is a Go app serving server-rendered pages. Shipping a React component library to all of those is a non-starter. So I built a small ",{"type":15,"tag":23,"props":24,"children":25},"strong",{},[26],{"type":20,"value":27},"web component",{"type":20,"value":29}," library instead: real custom elements that work anywhere a ",{"type":15,"tag":31,"props":32,"children":34},"code",{"className":33},[],[35],{"type":20,"value":36},"\u003Cscript>",{"type":20,"value":38}," tag does.",{"type":15,"tag":16,"props":40,"children":41},{},[42,44,49,51,56],{"type":20,"value":43},"The project pairs ",{"type":15,"tag":23,"props":45,"children":46},{},[47],{"type":20,"value":48},"Lit",{"type":20,"value":50}," for the components with ",{"type":15,"tag":23,"props":52,"children":53},{},[54],{"type":20,"value":55},"Astro",{"type":20,"value":57}," for the docs site, and the thing I'm happiest with is that both are driven from a single registry file.",{"type":15,"tag":59,"props":60,"children":62},"h2",{"id":61},"why-web-components",[63],{"type":20,"value":64},"Why web components",{"type":15,"tag":16,"props":66,"children":67},{},[68,70,76,78,84],{"type":20,"value":69},"The pitch is simple: a custom element is just an element. Once it's defined you use it like ",{"type":15,"tag":31,"props":71,"children":73},{"className":72},[],[74],{"type":20,"value":75},"\u003Cam-toggle>",{"type":20,"value":77}," in any HTML, regardless of framework. No adapter, no wrapper, no peer-dependency dance. Lit makes authoring them pleasant without dragging in a heavy runtime, a component is a class with reactive properties and a ",{"type":15,"tag":31,"props":79,"children":81},{"className":80},[],[82],{"type":20,"value":83},"render()",{"type":20,"value":85}," method:",{"type":15,"tag":87,"props":88,"children":92},"pre",{"className":89,"code":90,"language":91,"meta":7,"style":7},"language-ts shiki shiki-themes github-dark","import { LitElement, html, css } from 'lit';\n\nexport class Toggle extends LitElement {\n  static styles = css`\n    button { width: 48px; height: 28px; border-radius: 14px; background: #262626; }\n    button[aria-checked=\"true\"] { background: #22c55e; }\n    .thumb { transition: transform 0.2s ease; }\n    button[aria-checked=\"true\"] .thumb { transform: translateX(20px); }\n  `;\n\n  static properties = {\n    checked: { type: Boolean, reflect: true },\n  };\n\n  private toggle() {\n    this.checked = !this.checked;\n    this.dispatchEvent(new CustomEvent('change', {\n      detail: { checked: this.checked },\n      bubbles: true,\n      composed: true,\n    }));\n  }\n\n  render() {\n    return html`\n      \u003Cbutton role=\"switch\" aria-checked=\"${this.checked}\" @click=\"${this.toggle}\" part=\"switch\">\n        \u003Cspan class=\"thumb\" part=\"thumb\">\u003C/span>\n      \u003C/button>\n    `;\n  }\n}\n\ncustomElements.define('am-toggle', Toggle);\n","ts",[93],{"type":15,"tag":31,"props":94,"children":95},{"__ignoreMap":7},[96,130,140,175,205,214,223,232,241,254,262,283,303,312,320,339,373,420,438,456,473,482,491,499,512,530,575,584,593,606,614,623,631],{"type":15,"tag":97,"props":98,"children":101},"span",{"class":99,"line":100},"line",1,[102,108,114,119,125],{"type":15,"tag":97,"props":103,"children":105},{"style":104},"--shiki-default:#F97583",[106],{"type":20,"value":107},"import",{"type":15,"tag":97,"props":109,"children":111},{"style":110},"--shiki-default:#E1E4E8",[112],{"type":20,"value":113}," { LitElement, html, css } ",{"type":15,"tag":97,"props":115,"children":116},{"style":104},[117],{"type":20,"value":118},"from",{"type":15,"tag":97,"props":120,"children":122},{"style":121},"--shiki-default:#9ECBFF",[123],{"type":20,"value":124}," 'lit'",{"type":15,"tag":97,"props":126,"children":127},{"style":110},[128],{"type":20,"value":129},";\n",{"type":15,"tag":97,"props":131,"children":133},{"class":99,"line":132},2,[134],{"type":15,"tag":97,"props":135,"children":137},{"emptyLinePlaceholder":136},true,[138],{"type":20,"value":139},"\n",{"type":15,"tag":97,"props":141,"children":143},{"class":99,"line":142},3,[144,149,154,160,165,170],{"type":15,"tag":97,"props":145,"children":146},{"style":104},[147],{"type":20,"value":148},"export",{"type":15,"tag":97,"props":150,"children":151},{"style":104},[152],{"type":20,"value":153}," class",{"type":15,"tag":97,"props":155,"children":157},{"style":156},"--shiki-default:#B392F0",[158],{"type":20,"value":159}," Toggle",{"type":15,"tag":97,"props":161,"children":162},{"style":104},[163],{"type":20,"value":164}," extends",{"type":15,"tag":97,"props":166,"children":167},{"style":156},[168],{"type":20,"value":169}," LitElement",{"type":15,"tag":97,"props":171,"children":172},{"style":110},[173],{"type":20,"value":174}," {\n",{"type":15,"tag":97,"props":176,"children":178},{"class":99,"line":177},4,[179,184,190,195,200],{"type":15,"tag":97,"props":180,"children":181},{"style":104},[182],{"type":20,"value":183},"  static",{"type":15,"tag":97,"props":185,"children":187},{"style":186},"--shiki-default:#FFAB70",[188],{"type":20,"value":189}," styles",{"type":15,"tag":97,"props":191,"children":192},{"style":104},[193],{"type":20,"value":194}," =",{"type":15,"tag":97,"props":196,"children":197},{"style":156},[198],{"type":20,"value":199}," css",{"type":15,"tag":97,"props":201,"children":202},{"style":121},[203],{"type":20,"value":204},"`\n",{"type":15,"tag":97,"props":206,"children":208},{"class":99,"line":207},5,[209],{"type":15,"tag":97,"props":210,"children":211},{"style":121},[212],{"type":20,"value":213},"    button { width: 48px; height: 28px; border-radius: 14px; background: #262626; }\n",{"type":15,"tag":97,"props":215,"children":217},{"class":99,"line":216},6,[218],{"type":15,"tag":97,"props":219,"children":220},{"style":121},[221],{"type":20,"value":222},"    button[aria-checked=\"true\"] { background: #22c55e; }\n",{"type":15,"tag":97,"props":224,"children":226},{"class":99,"line":225},7,[227],{"type":15,"tag":97,"props":228,"children":229},{"style":121},[230],{"type":20,"value":231},"    .thumb { transition: transform 0.2s ease; }\n",{"type":15,"tag":97,"props":233,"children":235},{"class":99,"line":234},8,[236],{"type":15,"tag":97,"props":237,"children":238},{"style":121},[239],{"type":20,"value":240},"    button[aria-checked=\"true\"] .thumb { transform: translateX(20px); }\n",{"type":15,"tag":97,"props":242,"children":244},{"class":99,"line":243},9,[245,250],{"type":15,"tag":97,"props":246,"children":247},{"style":121},[248],{"type":20,"value":249},"  `",{"type":15,"tag":97,"props":251,"children":252},{"style":110},[253],{"type":20,"value":129},{"type":15,"tag":97,"props":255,"children":257},{"class":99,"line":256},10,[258],{"type":15,"tag":97,"props":259,"children":260},{"emptyLinePlaceholder":136},[261],{"type":20,"value":139},{"type":15,"tag":97,"props":263,"children":265},{"class":99,"line":264},11,[266,270,275,279],{"type":15,"tag":97,"props":267,"children":268},{"style":104},[269],{"type":20,"value":183},{"type":15,"tag":97,"props":271,"children":272},{"style":186},[273],{"type":20,"value":274}," properties",{"type":15,"tag":97,"props":276,"children":277},{"style":104},[278],{"type":20,"value":194},{"type":15,"tag":97,"props":280,"children":281},{"style":110},[282],{"type":20,"value":174},{"type":15,"tag":97,"props":284,"children":286},{"class":99,"line":285},12,[287,292,298],{"type":15,"tag":97,"props":288,"children":289},{"style":110},[290],{"type":20,"value":291},"    checked: { type: Boolean, reflect: ",{"type":15,"tag":97,"props":293,"children":295},{"style":294},"--shiki-default:#79B8FF",[296],{"type":20,"value":297},"true",{"type":15,"tag":97,"props":299,"children":300},{"style":110},[301],{"type":20,"value":302}," },\n",{"type":15,"tag":97,"props":304,"children":306},{"class":99,"line":305},13,[307],{"type":15,"tag":97,"props":308,"children":309},{"style":110},[310],{"type":20,"value":311},"  };\n",{"type":15,"tag":97,"props":313,"children":315},{"class":99,"line":314},14,[316],{"type":15,"tag":97,"props":317,"children":318},{"emptyLinePlaceholder":136},[319],{"type":20,"value":139},{"type":15,"tag":97,"props":321,"children":323},{"class":99,"line":322},15,[324,329,334],{"type":15,"tag":97,"props":325,"children":326},{"style":104},[327],{"type":20,"value":328},"  private",{"type":15,"tag":97,"props":330,"children":331},{"style":156},[332],{"type":20,"value":333}," toggle",{"type":15,"tag":97,"props":335,"children":336},{"style":110},[337],{"type":20,"value":338},"() {\n",{"type":15,"tag":97,"props":340,"children":342},{"class":99,"line":341},16,[343,348,353,358,363,368],{"type":15,"tag":97,"props":344,"children":345},{"style":294},[346],{"type":20,"value":347},"    this",{"type":15,"tag":97,"props":349,"children":350},{"style":110},[351],{"type":20,"value":352},".checked ",{"type":15,"tag":97,"props":354,"children":355},{"style":104},[356],{"type":20,"value":357},"=",{"type":15,"tag":97,"props":359,"children":360},{"style":104},[361],{"type":20,"value":362}," !",{"type":15,"tag":97,"props":364,"children":365},{"style":294},[366],{"type":20,"value":367},"this",{"type":15,"tag":97,"props":369,"children":370},{"style":110},[371],{"type":20,"value":372},".checked;\n",{"type":15,"tag":97,"props":374,"children":376},{"class":99,"line":375},17,[377,381,386,391,396,401,406,410,415],{"type":15,"tag":97,"props":378,"children":379},{"style":294},[380],{"type":20,"value":347},{"type":15,"tag":97,"props":382,"children":383},{"style":110},[384],{"type":20,"value":385},".",{"type":15,"tag":97,"props":387,"children":388},{"style":156},[389],{"type":20,"value":390},"dispatchEvent",{"type":15,"tag":97,"props":392,"children":393},{"style":110},[394],{"type":20,"value":395},"(",{"type":15,"tag":97,"props":397,"children":398},{"style":104},[399],{"type":20,"value":400},"new",{"type":15,"tag":97,"props":402,"children":403},{"style":156},[404],{"type":20,"value":405}," CustomEvent",{"type":15,"tag":97,"props":407,"children":408},{"style":110},[409],{"type":20,"value":395},{"type":15,"tag":97,"props":411,"children":412},{"style":121},[413],{"type":20,"value":414},"'change'",{"type":15,"tag":97,"props":416,"children":417},{"style":110},[418],{"type":20,"value":419},", {\n",{"type":15,"tag":97,"props":421,"children":423},{"class":99,"line":422},18,[424,429,433],{"type":15,"tag":97,"props":425,"children":426},{"style":110},[427],{"type":20,"value":428},"      detail: { checked: ",{"type":15,"tag":97,"props":430,"children":431},{"style":294},[432],{"type":20,"value":367},{"type":15,"tag":97,"props":434,"children":435},{"style":110},[436],{"type":20,"value":437},".checked },\n",{"type":15,"tag":97,"props":439,"children":441},{"class":99,"line":440},19,[442,447,451],{"type":15,"tag":97,"props":443,"children":444},{"style":110},[445],{"type":20,"value":446},"      bubbles: ",{"type":15,"tag":97,"props":448,"children":449},{"style":294},[450],{"type":20,"value":297},{"type":15,"tag":97,"props":452,"children":453},{"style":110},[454],{"type":20,"value":455},",\n",{"type":15,"tag":97,"props":457,"children":459},{"class":99,"line":458},20,[460,465,469],{"type":15,"tag":97,"props":461,"children":462},{"style":110},[463],{"type":20,"value":464},"      composed: ",{"type":15,"tag":97,"props":466,"children":467},{"style":294},[468],{"type":20,"value":297},{"type":15,"tag":97,"props":470,"children":471},{"style":110},[472],{"type":20,"value":455},{"type":15,"tag":97,"props":474,"children":476},{"class":99,"line":475},21,[477],{"type":15,"tag":97,"props":478,"children":479},{"style":110},[480],{"type":20,"value":481},"    }));\n",{"type":15,"tag":97,"props":483,"children":485},{"class":99,"line":484},22,[486],{"type":15,"tag":97,"props":487,"children":488},{"style":110},[489],{"type":20,"value":490},"  }\n",{"type":15,"tag":97,"props":492,"children":494},{"class":99,"line":493},23,[495],{"type":15,"tag":97,"props":496,"children":497},{"emptyLinePlaceholder":136},[498],{"type":20,"value":139},{"type":15,"tag":97,"props":500,"children":502},{"class":99,"line":501},24,[503,508],{"type":15,"tag":97,"props":504,"children":505},{"style":156},[506],{"type":20,"value":507},"  render",{"type":15,"tag":97,"props":509,"children":510},{"style":110},[511],{"type":20,"value":338},{"type":15,"tag":97,"props":513,"children":515},{"class":99,"line":514},25,[516,521,526],{"type":15,"tag":97,"props":517,"children":518},{"style":104},[519],{"type":20,"value":520},"    return",{"type":15,"tag":97,"props":522,"children":523},{"style":156},[524],{"type":20,"value":525}," html",{"type":15,"tag":97,"props":527,"children":528},{"style":121},[529],{"type":20,"value":204},{"type":15,"tag":97,"props":531,"children":533},{"class":99,"line":532},26,[534,539,543,547,552,557,561,565,570],{"type":15,"tag":97,"props":535,"children":536},{"style":121},[537],{"type":20,"value":538},"      \u003Cbutton role=\"switch\" aria-checked=\"${",{"type":15,"tag":97,"props":540,"children":541},{"style":294},[542],{"type":20,"value":367},{"type":15,"tag":97,"props":544,"children":545},{"style":121},[546],{"type":20,"value":385},{"type":15,"tag":97,"props":548,"children":549},{"style":110},[550],{"type":20,"value":551},"checked",{"type":15,"tag":97,"props":553,"children":554},{"style":121},[555],{"type":20,"value":556},"}\" @click=\"${",{"type":15,"tag":97,"props":558,"children":559},{"style":294},[560],{"type":20,"value":367},{"type":15,"tag":97,"props":562,"children":563},{"style":121},[564],{"type":20,"value":385},{"type":15,"tag":97,"props":566,"children":567},{"style":110},[568],{"type":20,"value":569},"toggle",{"type":15,"tag":97,"props":571,"children":572},{"style":121},[573],{"type":20,"value":574},"}\" part=\"switch\">\n",{"type":15,"tag":97,"props":576,"children":578},{"class":99,"line":577},27,[579],{"type":15,"tag":97,"props":580,"children":581},{"style":121},[582],{"type":20,"value":583},"        \u003Cspan class=\"thumb\" part=\"thumb\">\u003C/span>\n",{"type":15,"tag":97,"props":585,"children":587},{"class":99,"line":586},28,[588],{"type":15,"tag":97,"props":589,"children":590},{"style":121},[591],{"type":20,"value":592},"      \u003C/button>\n",{"type":15,"tag":97,"props":594,"children":596},{"class":99,"line":595},29,[597,602],{"type":15,"tag":97,"props":598,"children":599},{"style":121},[600],{"type":20,"value":601},"    `",{"type":15,"tag":97,"props":603,"children":604},{"style":110},[605],{"type":20,"value":129},{"type":15,"tag":97,"props":607,"children":609},{"class":99,"line":608},30,[610],{"type":15,"tag":97,"props":611,"children":612},{"style":110},[613],{"type":20,"value":490},{"type":15,"tag":97,"props":615,"children":617},{"class":99,"line":616},31,[618],{"type":15,"tag":97,"props":619,"children":620},{"style":110},[621],{"type":20,"value":622},"}\n",{"type":15,"tag":97,"props":624,"children":626},{"class":99,"line":625},32,[627],{"type":15,"tag":97,"props":628,"children":629},{"emptyLinePlaceholder":136},[630],{"type":20,"value":139},{"type":15,"tag":97,"props":632,"children":634},{"class":99,"line":633},33,[635,640,645,649,654],{"type":15,"tag":97,"props":636,"children":637},{"style":110},[638],{"type":20,"value":639},"customElements.",{"type":15,"tag":97,"props":641,"children":642},{"style":156},[643],{"type":20,"value":644},"define",{"type":15,"tag":97,"props":646,"children":647},{"style":110},[648],{"type":20,"value":395},{"type":15,"tag":97,"props":650,"children":651},{"style":121},[652],{"type":20,"value":653},"'am-toggle'",{"type":15,"tag":97,"props":655,"children":656},{"style":110},[657],{"type":20,"value":658},", Toggle);\n",{"type":15,"tag":16,"props":660,"children":661},{},[662,664,670,672,678,680,686,688,694,696,702,704,710],{"type":20,"value":663},"A couple of details I made a point of getting right: the ",{"type":15,"tag":31,"props":665,"children":667},{"className":666},[],[668],{"type":20,"value":669},"change",{"type":20,"value":671}," event is dispatched with ",{"type":15,"tag":31,"props":673,"children":675},{"className":674},[],[676],{"type":20,"value":677},"bubbles: true, composed: true",{"type":20,"value":679}," so it actually crosses the shadow DOM boundary and reaches listeners outside the component, and I expose ",{"type":15,"tag":31,"props":681,"children":683},{"className":682},[],[684],{"type":20,"value":685},"part=\"switch\"",{"type":20,"value":687}," / ",{"type":15,"tag":31,"props":689,"children":691},{"className":690},[],[692],{"type":20,"value":693},"part=\"thumb\"",{"type":20,"value":695}," so consumers can restyle internals with ",{"type":15,"tag":31,"props":697,"children":699},{"className":698},[],[700],{"type":20,"value":701},"::part()",{"type":20,"value":703}," without me leaking my whole stylesheet. Everything is prefixed ",{"type":15,"tag":31,"props":705,"children":707},{"className":706},[],[708],{"type":20,"value":709},"am-",{"type":20,"value":711}," to avoid collisions with anyone else's elements.",{"type":15,"tag":59,"props":713,"children":715},{"id":714},"one-registry-two-outputs",[716],{"type":20,"value":717},"One registry, two outputs",{"type":15,"tag":16,"props":719,"children":720},{},[721,723,729],{"type":20,"value":722},"The piece that ties it together is ",{"type":15,"tag":31,"props":724,"children":726},{"className":725},[],[727],{"type":20,"value":728},"src/lib/registry.ts",{"type":20,"value":730},". It's the single source of truth, a typed list of components, each describing its name, description, and its attributes (type, options, defaults):",{"type":15,"tag":87,"props":732,"children":734},{"className":89,"code":733,"language":91,"meta":7,"style":7},"export const PREFIX = 'am';\n\nexport const components: Component[] = [\n  {\n    name: 'button',\n    description: 'A button with variants and sizes.',\n    attrs: [\n      { name: 'variant', type: 'select', options: ['primary', 'secondary', 'ghost'], default: 'primary' },\n      { name: 'size', type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },\n    ],\n    content: 'Click me',\n  },\n  // toggle, counter, brick-background, template...\n];\n\nexport const tag = (name: string) => `${PREFIX}-${name}`;\nexport const src = (name: string) => `/components/${name}.js`;\nexport const href = (name: string) => `/docs/${name}`;\n",[735],{"type":15,"tag":31,"props":736,"children":737},{"__ignoreMap":7},[738,768,775,815,823,840,857,865,930,989,997,1014,1022,1031,1039,1046,1123,1185],{"type":15,"tag":97,"props":739,"children":740},{"class":99,"line":100},[741,745,750,755,759,764],{"type":15,"tag":97,"props":742,"children":743},{"style":104},[744],{"type":20,"value":148},{"type":15,"tag":97,"props":746,"children":747},{"style":104},[748],{"type":20,"value":749}," const",{"type":15,"tag":97,"props":751,"children":752},{"style":294},[753],{"type":20,"value":754}," PREFIX",{"type":15,"tag":97,"props":756,"children":757},{"style":104},[758],{"type":20,"value":194},{"type":15,"tag":97,"props":760,"children":761},{"style":121},[762],{"type":20,"value":763}," 'am'",{"type":15,"tag":97,"props":765,"children":766},{"style":110},[767],{"type":20,"value":129},{"type":15,"tag":97,"props":769,"children":770},{"class":99,"line":132},[771],{"type":15,"tag":97,"props":772,"children":773},{"emptyLinePlaceholder":136},[774],{"type":20,"value":139},{"type":15,"tag":97,"props":776,"children":777},{"class":99,"line":142},[778,782,786,791,796,801,806,810],{"type":15,"tag":97,"props":779,"children":780},{"style":104},[781],{"type":20,"value":148},{"type":15,"tag":97,"props":783,"children":784},{"style":104},[785],{"type":20,"value":749},{"type":15,"tag":97,"props":787,"children":788},{"style":294},[789],{"type":20,"value":790}," components",{"type":15,"tag":97,"props":792,"children":793},{"style":104},[794],{"type":20,"value":795},":",{"type":15,"tag":97,"props":797,"children":798},{"style":156},[799],{"type":20,"value":800}," Component",{"type":15,"tag":97,"props":802,"children":803},{"style":110},[804],{"type":20,"value":805},"[] ",{"type":15,"tag":97,"props":807,"children":808},{"style":104},[809],{"type":20,"value":357},{"type":15,"tag":97,"props":811,"children":812},{"style":110},[813],{"type":20,"value":814}," [\n",{"type":15,"tag":97,"props":816,"children":817},{"class":99,"line":177},[818],{"type":15,"tag":97,"props":819,"children":820},{"style":110},[821],{"type":20,"value":822},"  {\n",{"type":15,"tag":97,"props":824,"children":825},{"class":99,"line":207},[826,831,836],{"type":15,"tag":97,"props":827,"children":828},{"style":110},[829],{"type":20,"value":830},"    name: ",{"type":15,"tag":97,"props":832,"children":833},{"style":121},[834],{"type":20,"value":835},"'button'",{"type":15,"tag":97,"props":837,"children":838},{"style":110},[839],{"type":20,"value":455},{"type":15,"tag":97,"props":841,"children":842},{"class":99,"line":216},[843,848,853],{"type":15,"tag":97,"props":844,"children":845},{"style":110},[846],{"type":20,"value":847},"    description: ",{"type":15,"tag":97,"props":849,"children":850},{"style":121},[851],{"type":20,"value":852},"'A button with variants and sizes.'",{"type":15,"tag":97,"props":854,"children":855},{"style":110},[856],{"type":20,"value":455},{"type":15,"tag":97,"props":858,"children":859},{"class":99,"line":225},[860],{"type":15,"tag":97,"props":861,"children":862},{"style":110},[863],{"type":20,"value":864},"    attrs: [\n",{"type":15,"tag":97,"props":866,"children":867},{"class":99,"line":234},[868,873,878,883,888,893,898,903,908,912,917,922,926],{"type":15,"tag":97,"props":869,"children":870},{"style":110},[871],{"type":20,"value":872},"      { name: ",{"type":15,"tag":97,"props":874,"children":875},{"style":121},[876],{"type":20,"value":877},"'variant'",{"type":15,"tag":97,"props":879,"children":880},{"style":110},[881],{"type":20,"value":882},", type: ",{"type":15,"tag":97,"props":884,"children":885},{"style":121},[886],{"type":20,"value":887},"'select'",{"type":15,"tag":97,"props":889,"children":890},{"style":110},[891],{"type":20,"value":892},", options: [",{"type":15,"tag":97,"props":894,"children":895},{"style":121},[896],{"type":20,"value":897},"'primary'",{"type":15,"tag":97,"props":899,"children":900},{"style":110},[901],{"type":20,"value":902},", ",{"type":15,"tag":97,"props":904,"children":905},{"style":121},[906],{"type":20,"value":907},"'secondary'",{"type":15,"tag":97,"props":909,"children":910},{"style":110},[911],{"type":20,"value":902},{"type":15,"tag":97,"props":913,"children":914},{"style":121},[915],{"type":20,"value":916},"'ghost'",{"type":15,"tag":97,"props":918,"children":919},{"style":110},[920],{"type":20,"value":921},"], default: ",{"type":15,"tag":97,"props":923,"children":924},{"style":121},[925],{"type":20,"value":897},{"type":15,"tag":97,"props":927,"children":928},{"style":110},[929],{"type":20,"value":302},{"type":15,"tag":97,"props":931,"children":932},{"class":99,"line":243},[933,937,942,946,950,954,959,963,968,972,977,981,985],{"type":15,"tag":97,"props":934,"children":935},{"style":110},[936],{"type":20,"value":872},{"type":15,"tag":97,"props":938,"children":939},{"style":121},[940],{"type":20,"value":941},"'size'",{"type":15,"tag":97,"props":943,"children":944},{"style":110},[945],{"type":20,"value":882},{"type":15,"tag":97,"props":947,"children":948},{"style":121},[949],{"type":20,"value":887},{"type":15,"tag":97,"props":951,"children":952},{"style":110},[953],{"type":20,"value":892},{"type":15,"tag":97,"props":955,"children":956},{"style":121},[957],{"type":20,"value":958},"'sm'",{"type":15,"tag":97,"props":960,"children":961},{"style":110},[962],{"type":20,"value":902},{"type":15,"tag":97,"props":964,"children":965},{"style":121},[966],{"type":20,"value":967},"'md'",{"type":15,"tag":97,"props":969,"children":970},{"style":110},[971],{"type":20,"value":902},{"type":15,"tag":97,"props":973,"children":974},{"style":121},[975],{"type":20,"value":976},"'lg'",{"type":15,"tag":97,"props":978,"children":979},{"style":110},[980],{"type":20,"value":921},{"type":15,"tag":97,"props":982,"children":983},{"style":121},[984],{"type":20,"value":967},{"type":15,"tag":97,"props":986,"children":987},{"style":110},[988],{"type":20,"value":302},{"type":15,"tag":97,"props":990,"children":991},{"class":99,"line":256},[992],{"type":15,"tag":97,"props":993,"children":994},{"style":110},[995],{"type":20,"value":996},"    ],\n",{"type":15,"tag":97,"props":998,"children":999},{"class":99,"line":264},[1000,1005,1010],{"type":15,"tag":97,"props":1001,"children":1002},{"style":110},[1003],{"type":20,"value":1004},"    content: ",{"type":15,"tag":97,"props":1006,"children":1007},{"style":121},[1008],{"type":20,"value":1009},"'Click me'",{"type":15,"tag":97,"props":1011,"children":1012},{"style":110},[1013],{"type":20,"value":455},{"type":15,"tag":97,"props":1015,"children":1016},{"class":99,"line":285},[1017],{"type":15,"tag":97,"props":1018,"children":1019},{"style":110},[1020],{"type":20,"value":1021},"  },\n",{"type":15,"tag":97,"props":1023,"children":1024},{"class":99,"line":305},[1025],{"type":15,"tag":97,"props":1026,"children":1028},{"style":1027},"--shiki-default:#6A737D",[1029],{"type":20,"value":1030},"  // toggle, counter, brick-background, template...\n",{"type":15,"tag":97,"props":1032,"children":1033},{"class":99,"line":314},[1034],{"type":15,"tag":97,"props":1035,"children":1036},{"style":110},[1037],{"type":20,"value":1038},"];\n",{"type":15,"tag":97,"props":1040,"children":1041},{"class":99,"line":322},[1042],{"type":15,"tag":97,"props":1043,"children":1044},{"emptyLinePlaceholder":136},[1045],{"type":20,"value":139},{"type":15,"tag":97,"props":1047,"children":1048},{"class":99,"line":341},[1049,1053,1057,1062,1066,1071,1076,1080,1085,1090,1095,1100,1105,1110,1114,1119],{"type":15,"tag":97,"props":1050,"children":1051},{"style":104},[1052],{"type":20,"value":148},{"type":15,"tag":97,"props":1054,"children":1055},{"style":104},[1056],{"type":20,"value":749},{"type":15,"tag":97,"props":1058,"children":1059},{"style":156},[1060],{"type":20,"value":1061}," tag",{"type":15,"tag":97,"props":1063,"children":1064},{"style":104},[1065],{"type":20,"value":194},{"type":15,"tag":97,"props":1067,"children":1068},{"style":110},[1069],{"type":20,"value":1070}," (",{"type":15,"tag":97,"props":1072,"children":1073},{"style":186},[1074],{"type":20,"value":1075},"name",{"type":15,"tag":97,"props":1077,"children":1078},{"style":104},[1079],{"type":20,"value":795},{"type":15,"tag":97,"props":1081,"children":1082},{"style":294},[1083],{"type":20,"value":1084}," string",{"type":15,"tag":97,"props":1086,"children":1087},{"style":110},[1088],{"type":20,"value":1089},") ",{"type":15,"tag":97,"props":1091,"children":1092},{"style":104},[1093],{"type":20,"value":1094},"=>",{"type":15,"tag":97,"props":1096,"children":1097},{"style":121},[1098],{"type":20,"value":1099}," `${",{"type":15,"tag":97,"props":1101,"children":1102},{"style":294},[1103],{"type":20,"value":1104},"PREFIX",{"type":15,"tag":97,"props":1106,"children":1107},{"style":121},[1108],{"type":20,"value":1109},"}-${",{"type":15,"tag":97,"props":1111,"children":1112},{"style":110},[1113],{"type":20,"value":1075},{"type":15,"tag":97,"props":1115,"children":1116},{"style":121},[1117],{"type":20,"value":1118},"}`",{"type":15,"tag":97,"props":1120,"children":1121},{"style":110},[1122],{"type":20,"value":129},{"type":15,"tag":97,"props":1124,"children":1125},{"class":99,"line":375},[1126,1130,1134,1139,1143,1147,1151,1155,1159,1163,1167,1172,1176,1181],{"type":15,"tag":97,"props":1127,"children":1128},{"style":104},[1129],{"type":20,"value":148},{"type":15,"tag":97,"props":1131,"children":1132},{"style":104},[1133],{"type":20,"value":749},{"type":15,"tag":97,"props":1135,"children":1136},{"style":156},[1137],{"type":20,"value":1138}," src",{"type":15,"tag":97,"props":1140,"children":1141},{"style":104},[1142],{"type":20,"value":194},{"type":15,"tag":97,"props":1144,"children":1145},{"style":110},[1146],{"type":20,"value":1070},{"type":15,"tag":97,"props":1148,"children":1149},{"style":186},[1150],{"type":20,"value":1075},{"type":15,"tag":97,"props":1152,"children":1153},{"style":104},[1154],{"type":20,"value":795},{"type":15,"tag":97,"props":1156,"children":1157},{"style":294},[1158],{"type":20,"value":1084},{"type":15,"tag":97,"props":1160,"children":1161},{"style":110},[1162],{"type":20,"value":1089},{"type":15,"tag":97,"props":1164,"children":1165},{"style":104},[1166],{"type":20,"value":1094},{"type":15,"tag":97,"props":1168,"children":1169},{"style":121},[1170],{"type":20,"value":1171}," `/components/${",{"type":15,"tag":97,"props":1173,"children":1174},{"style":110},[1175],{"type":20,"value":1075},{"type":15,"tag":97,"props":1177,"children":1178},{"style":121},[1179],{"type":20,"value":1180},"}.js`",{"type":15,"tag":97,"props":1182,"children":1183},{"style":110},[1184],{"type":20,"value":129},{"type":15,"tag":97,"props":1186,"children":1187},{"class":99,"line":422},[1188,1192,1196,1201,1205,1209,1213,1217,1221,1225,1229,1234,1238,1242],{"type":15,"tag":97,"props":1189,"children":1190},{"style":104},[1191],{"type":20,"value":148},{"type":15,"tag":97,"props":1193,"children":1194},{"style":104},[1195],{"type":20,"value":749},{"type":15,"tag":97,"props":1197,"children":1198},{"style":156},[1199],{"type":20,"value":1200}," href",{"type":15,"tag":97,"props":1202,"children":1203},{"style":104},[1204],{"type":20,"value":194},{"type":15,"tag":97,"props":1206,"children":1207},{"style":110},[1208],{"type":20,"value":1070},{"type":15,"tag":97,"props":1210,"children":1211},{"style":186},[1212],{"type":20,"value":1075},{"type":15,"tag":97,"props":1214,"children":1215},{"style":104},[1216],{"type":20,"value":795},{"type":15,"tag":97,"props":1218,"children":1219},{"style":294},[1220],{"type":20,"value":1084},{"type":15,"tag":97,"props":1222,"children":1223},{"style":110},[1224],{"type":20,"value":1089},{"type":15,"tag":97,"props":1226,"children":1227},{"style":104},[1228],{"type":20,"value":1094},{"type":15,"tag":97,"props":1230,"children":1231},{"style":121},[1232],{"type":20,"value":1233}," `/docs/${",{"type":15,"tag":97,"props":1235,"children":1236},{"style":110},[1237],{"type":20,"value":1075},{"type":15,"tag":97,"props":1239,"children":1240},{"style":121},[1241],{"type":20,"value":1118},{"type":15,"tag":97,"props":1243,"children":1244},{"style":110},[1245],{"type":20,"value":129},{"type":15,"tag":16,"props":1247,"children":1248},{},[1249,1251,1257,1259,1265],{"type":20,"value":1250},"That registry drives the navigation, the per-component docs pages, and the interactive preview's attribute controls. When I add a component, I add one entry and the docs site grows itself. The docs pages live in Astro's file-based routing, a single ",{"type":15,"tag":31,"props":1252,"children":1254},{"className":1253},[],[1255],{"type":20,"value":1256},"src/pages/docs/[component].astro",{"type":20,"value":1258}," dynamic route renders a page for every entry in the registry, with an attribute panel built from each component's ",{"type":15,"tag":31,"props":1260,"children":1262},{"className":1261},[],[1263],{"type":20,"value":1264},"attrs",{"type":20,"value":385},{"type":15,"tag":59,"props":1267,"children":1269},{"id":1268},"building-distributable-bundles",[1270],{"type":20,"value":1271},"Building distributable bundles",{"type":15,"tag":16,"props":1273,"children":1274},{},[1275,1277,1283,1285,1291],{"type":20,"value":1276},"Astro builds the docs site, but the ",{"type":15,"tag":1278,"props":1279,"children":1280},"em",{},[1281],{"type":20,"value":1282},"components",{"type":20,"value":1284}," need to ship as standalone JS that anyone can drop into a page. That's a separate esbuild step (",{"type":15,"tag":31,"props":1286,"children":1288},{"className":1287},[],[1289],{"type":20,"value":1290},"scripts/build-components.js",{"type":20,"value":1292},") wired into the build:",{"type":15,"tag":87,"props":1294,"children":1298},{"className":1295,"code":1296,"language":1297,"meta":7,"style":7},"language-js shiki shiki-themes github-dark","import * as esbuild from 'esbuild';\n\nawait esbuild.build({\n  entryPoints: [join(componentsDir, file)],\n  outfile: join(outDir, `${name}.js`),\n  bundle: true,\n  format: 'esm',\n  target: 'es2020',\n  minify: true,\n  external: [], // bundle Lit in too, consumers shouldn't have to install anything\n});\n","js",[1299],{"type":15,"tag":31,"props":1300,"children":1301},{"__ignoreMap":7},[1302,1337,1344,1367,1385,1420,1436,1453,1470,1486,1499],{"type":15,"tag":97,"props":1303,"children":1304},{"class":99,"line":100},[1305,1309,1314,1319,1324,1328,1333],{"type":15,"tag":97,"props":1306,"children":1307},{"style":104},[1308],{"type":20,"value":107},{"type":15,"tag":97,"props":1310,"children":1311},{"style":294},[1312],{"type":20,"value":1313}," *",{"type":15,"tag":97,"props":1315,"children":1316},{"style":104},[1317],{"type":20,"value":1318}," as",{"type":15,"tag":97,"props":1320,"children":1321},{"style":110},[1322],{"type":20,"value":1323}," esbuild ",{"type":15,"tag":97,"props":1325,"children":1326},{"style":104},[1327],{"type":20,"value":118},{"type":15,"tag":97,"props":1329,"children":1330},{"style":121},[1331],{"type":20,"value":1332}," 'esbuild'",{"type":15,"tag":97,"props":1334,"children":1335},{"style":110},[1336],{"type":20,"value":129},{"type":15,"tag":97,"props":1338,"children":1339},{"class":99,"line":132},[1340],{"type":15,"tag":97,"props":1341,"children":1342},{"emptyLinePlaceholder":136},[1343],{"type":20,"value":139},{"type":15,"tag":97,"props":1345,"children":1346},{"class":99,"line":142},[1347,1352,1357,1362],{"type":15,"tag":97,"props":1348,"children":1349},{"style":104},[1350],{"type":20,"value":1351},"await",{"type":15,"tag":97,"props":1353,"children":1354},{"style":110},[1355],{"type":20,"value":1356}," esbuild.",{"type":15,"tag":97,"props":1358,"children":1359},{"style":156},[1360],{"type":20,"value":1361},"build",{"type":15,"tag":97,"props":1363,"children":1364},{"style":110},[1365],{"type":20,"value":1366},"({\n",{"type":15,"tag":97,"props":1368,"children":1369},{"class":99,"line":177},[1370,1375,1380],{"type":15,"tag":97,"props":1371,"children":1372},{"style":110},[1373],{"type":20,"value":1374},"  entryPoints: [",{"type":15,"tag":97,"props":1376,"children":1377},{"style":156},[1378],{"type":20,"value":1379},"join",{"type":15,"tag":97,"props":1381,"children":1382},{"style":110},[1383],{"type":20,"value":1384},"(componentsDir, file)],\n",{"type":15,"tag":97,"props":1386,"children":1387},{"class":99,"line":207},[1388,1393,1397,1402,1407,1411,1415],{"type":15,"tag":97,"props":1389,"children":1390},{"style":110},[1391],{"type":20,"value":1392},"  outfile: ",{"type":15,"tag":97,"props":1394,"children":1395},{"style":156},[1396],{"type":20,"value":1379},{"type":15,"tag":97,"props":1398,"children":1399},{"style":110},[1400],{"type":20,"value":1401},"(outDir, ",{"type":15,"tag":97,"props":1403,"children":1404},{"style":121},[1405],{"type":20,"value":1406},"`${",{"type":15,"tag":97,"props":1408,"children":1409},{"style":110},[1410],{"type":20,"value":1075},{"type":15,"tag":97,"props":1412,"children":1413},{"style":121},[1414],{"type":20,"value":1180},{"type":15,"tag":97,"props":1416,"children":1417},{"style":110},[1418],{"type":20,"value":1419},"),\n",{"type":15,"tag":97,"props":1421,"children":1422},{"class":99,"line":216},[1423,1428,1432],{"type":15,"tag":97,"props":1424,"children":1425},{"style":110},[1426],{"type":20,"value":1427},"  bundle: ",{"type":15,"tag":97,"props":1429,"children":1430},{"style":294},[1431],{"type":20,"value":297},{"type":15,"tag":97,"props":1433,"children":1434},{"style":110},[1435],{"type":20,"value":455},{"type":15,"tag":97,"props":1437,"children":1438},{"class":99,"line":225},[1439,1444,1449],{"type":15,"tag":97,"props":1440,"children":1441},{"style":110},[1442],{"type":20,"value":1443},"  format: ",{"type":15,"tag":97,"props":1445,"children":1446},{"style":121},[1447],{"type":20,"value":1448},"'esm'",{"type":15,"tag":97,"props":1450,"children":1451},{"style":110},[1452],{"type":20,"value":455},{"type":15,"tag":97,"props":1454,"children":1455},{"class":99,"line":234},[1456,1461,1466],{"type":15,"tag":97,"props":1457,"children":1458},{"style":110},[1459],{"type":20,"value":1460},"  target: ",{"type":15,"tag":97,"props":1462,"children":1463},{"style":121},[1464],{"type":20,"value":1465},"'es2020'",{"type":15,"tag":97,"props":1467,"children":1468},{"style":110},[1469],{"type":20,"value":455},{"type":15,"tag":97,"props":1471,"children":1472},{"class":99,"line":243},[1473,1478,1482],{"type":15,"tag":97,"props":1474,"children":1475},{"style":110},[1476],{"type":20,"value":1477},"  minify: ",{"type":15,"tag":97,"props":1479,"children":1480},{"style":294},[1481],{"type":20,"value":297},{"type":15,"tag":97,"props":1483,"children":1484},{"style":110},[1485],{"type":20,"value":455},{"type":15,"tag":97,"props":1487,"children":1488},{"class":99,"line":256},[1489,1494],{"type":15,"tag":97,"props":1490,"children":1491},{"style":110},[1492],{"type":20,"value":1493},"  external: [], ",{"type":15,"tag":97,"props":1495,"children":1496},{"style":1027},[1497],{"type":20,"value":1498},"// bundle Lit in too, consumers shouldn't have to install anything\n",{"type":15,"tag":97,"props":1500,"children":1501},{"class":99,"line":264},[1502],{"type":15,"tag":97,"props":1503,"children":1504},{"style":110},[1505],{"type":20,"value":1506},"});\n",{"type":15,"tag":16,"props":1508,"children":1509},{},[1510,1512,1518],{"type":20,"value":1511},"It produces three flavours into ",{"type":15,"tag":31,"props":1513,"children":1515},{"className":1514},[],[1516],{"type":20,"value":1517},"public/components/",{"type":20,"value":795},{"type":15,"tag":1520,"props":1521,"children":1522},"ul",{},[1523,1537,1550],{"type":15,"tag":1524,"props":1525,"children":1526},"li",{},[1527,1529,1535],{"type":20,"value":1528},"one minified ",{"type":15,"tag":31,"props":1530,"children":1532},{"className":1531},[],[1533],{"type":20,"value":1534},"name.js",{"type":20,"value":1536}," per component, for when you only want one",{"type":15,"tag":1524,"props":1538,"children":1539},{},[1540,1542,1548],{"type":20,"value":1541},"a ",{"type":15,"tag":31,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":20,"value":1547},"components.js",{"type":20,"value":1549}," bundle with everything",{"type":15,"tag":1524,"props":1551,"children":1552},{},[1553,1555,1561],{"type":20,"value":1554},"a non-minified ",{"type":15,"tag":31,"props":1556,"children":1558},{"className":1557},[],[1559],{"type":20,"value":1560},"components.dev.js",{"type":20,"value":1562}," for debugging",{"type":15,"tag":16,"props":1564,"children":1565},{},[1566,1568,1574,1576,1581],{"type":20,"value":1567},"The key choice is ",{"type":15,"tag":31,"props":1569,"children":1571},{"className":1570},[],[1572],{"type":20,"value":1573},"external: []",{"type":20,"value":1575},", Lit gets bundled ",{"type":15,"tag":1278,"props":1577,"children":1578},{},[1579],{"type":20,"value":1580},"into",{"type":20,"value":1582}," each output. That bloats the bytes slightly, but it means a consumer integrates with nothing more than:",{"type":15,"tag":87,"props":1584,"children":1588},{"className":1585,"code":1586,"language":1587,"meta":7,"style":7},"language-html shiki shiki-themes github-dark","\u003Cscript type=\"module\" src=\"https://.../components/components.js\">\u003C/script>\n\u003C!-- then just use them -->\n\u003Cam-toggle>\u003C/am-toggle>\n","html",[1589],{"type":15,"tag":31,"props":1590,"children":1591},{"__ignoreMap":7},[1592,1647,1655],{"type":15,"tag":97,"props":1593,"children":1594},{"class":99,"line":100},[1595,1600,1606,1611,1615,1620,1624,1628,1633,1638,1642],{"type":15,"tag":97,"props":1596,"children":1597},{"style":110},[1598],{"type":20,"value":1599},"\u003C",{"type":15,"tag":97,"props":1601,"children":1603},{"style":1602},"--shiki-default:#85E89D",[1604],{"type":20,"value":1605},"script",{"type":15,"tag":97,"props":1607,"children":1608},{"style":156},[1609],{"type":20,"value":1610}," type",{"type":15,"tag":97,"props":1612,"children":1613},{"style":110},[1614],{"type":20,"value":357},{"type":15,"tag":97,"props":1616,"children":1617},{"style":121},[1618],{"type":20,"value":1619},"\"module\"",{"type":15,"tag":97,"props":1621,"children":1622},{"style":156},[1623],{"type":20,"value":1138},{"type":15,"tag":97,"props":1625,"children":1626},{"style":110},[1627],{"type":20,"value":357},{"type":15,"tag":97,"props":1629,"children":1630},{"style":121},[1631],{"type":20,"value":1632},"\"https://.../components/components.js\"",{"type":15,"tag":97,"props":1634,"children":1635},{"style":110},[1636],{"type":20,"value":1637},">\u003C/",{"type":15,"tag":97,"props":1639,"children":1640},{"style":1602},[1641],{"type":20,"value":1605},{"type":15,"tag":97,"props":1643,"children":1644},{"style":110},[1645],{"type":20,"value":1646},">\n",{"type":15,"tag":97,"props":1648,"children":1649},{"class":99,"line":132},[1650],{"type":15,"tag":97,"props":1651,"children":1652},{"style":1027},[1653],{"type":20,"value":1654},"\u003C!-- then just use them -->\n",{"type":15,"tag":97,"props":1656,"children":1657},{"class":99,"line":142},[1658,1662,1667,1671,1675],{"type":15,"tag":97,"props":1659,"children":1660},{"style":110},[1661],{"type":20,"value":1599},{"type":15,"tag":97,"props":1663,"children":1664},{"style":1602},[1665],{"type":20,"value":1666},"am-toggle",{"type":15,"tag":97,"props":1668,"children":1669},{"style":110},[1670],{"type":20,"value":1637},{"type":15,"tag":97,"props":1672,"children":1673},{"style":1602},[1674],{"type":20,"value":1666},{"type":15,"tag":97,"props":1676,"children":1677},{"style":110},[1678],{"type":20,"value":1646},{"type":15,"tag":16,"props":1680,"children":1681},{},[1682],{"type":20,"value":1683},"No npm install, no bundler, no framework. Exactly the property I wanted.",{"type":15,"tag":59,"props":1685,"children":1687},{"id":1686},"what-id-flag",[1688],{"type":20,"value":1689},"What I'd flag",{"type":15,"tag":1520,"props":1691,"children":1692},{},[1693,1710,1734],{"type":15,"tag":1524,"props":1694,"children":1695},{},[1696,1701,1703,1708],{"type":15,"tag":23,"props":1697,"children":1698},{},[1699],{"type":20,"value":1700},"Bundling Lit per-file duplicates it",{"type":20,"value":1702}," if a page loads several individual component files. For multi-component pages, the combined ",{"type":15,"tag":31,"props":1704,"children":1706},{"className":1705},[],[1707],{"type":20,"value":1547},{"type":20,"value":1709}," is the right call; the single-file builds are for the \"I just want one toggle\" case.",{"type":15,"tag":1524,"props":1711,"children":1712},{},[1713,1718,1720,1725,1727,1732],{"type":15,"tag":23,"props":1714,"children":1715},{},[1716],{"type":20,"value":1717},"Shadow DOM styling is a real boundary.",{"type":20,"value":1719}," It's a feature (my styles don't leak out, page styles don't leak in), but it means you ",{"type":15,"tag":1278,"props":1721,"children":1722},{},[1723],{"type":20,"value":1724},"must",{"type":20,"value":1726}," think about theming up front. CSS custom properties and ",{"type":15,"tag":31,"props":1728,"children":1730},{"className":1729},[],[1731],{"type":20,"value":701},{"type":20,"value":1733}," are the escape hatches, and they only work if you expose them deliberately.",{"type":15,"tag":1524,"props":1735,"children":1736},{},[1737,1750],{"type":15,"tag":23,"props":1738,"children":1739},{},[1740,1742,1748],{"type":20,"value":1741},"The ",{"type":15,"tag":31,"props":1743,"children":1745},{"className":1744},[],[1746],{"type":20,"value":1747},"template.ts",{"type":20,"value":1749}," component",{"type":20,"value":1751}," is intentionally a copy-paste starting point. Lowering the barrier to adding the next component keeps the registry-driven flow honest.",{"type":15,"tag":16,"props":1753,"children":1754},{},[1755],{"type":20,"value":1756},"The result is a tiny library I can use literally anywhere, documented by a site that builds itself from a single file. For shared primitives across a mixed-stack collection of projects, web components turned out to be exactly the right level of abstraction.",{"type":15,"tag":1758,"props":1759,"children":1760},"style",{},[1761],{"type":20,"value":1762},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":132,"depth":132,"links":1764},[1765,1766,1767,1768],{"id":61,"depth":132,"text":64},{"id":714,"depth":132,"text":717},{"id":1268,"depth":132,"text":1271},{"id":1686,"depth":132,"text":1689},"markdown","content:blog:lit-web-components-astro-docs.md","content","blog/lit-web-components-astro-docs.md","blog/lit-web-components-astro-docs","md",[1776,1780,1784,1788,1792,1796,1800,1804,1808,1809],{"_path":1777,"title":1778,"date":1779},"/blog/deploying-nuxt-to-cloudflare-workers","Deploying this Nuxt site to Cloudflare Workers","2026-06-06",{"_path":1781,"title":1782,"date":1783},"/blog/building-forever-llm","Building forever-llm: three takes on a model that never stops","2026-05-20",{"_path":1785,"title":1786,"date":1787},"/blog/laravel-cortex-adhd-productivity","Building Cortex: An ADHD Productivity App in Laravel + Inertia","2026-05-12",{"_path":1789,"title":1790,"date":1791},"/blog/eink-spotify-weather-clock","Building an E-Ink Clock That Shows Spotify, Weather and the Time","2026-05-05",{"_path":1793,"title":1794,"date":1795},"/blog/hetzner-k8s-cluster","Building a K3s Cluster on Hetzner with Terraform and GitOps","2026-04-20",{"_path":1797,"title":1798,"date":1799},"/blog/arduino-uno-q-forza-rev-gauge","A Forza Rev Gauge on the Arduino UNO Q's LED Matrix","2026-04-15",{"_path":1801,"title":1802,"date":1803},"/blog/modular-go-echo-gorm","A Modular Go Web App Pattern with Echo, GORM and golang-migrate","2026-04-05",{"_path":1805,"title":1806,"date":1807},"/blog/self-hosted-ios-web-push","Self-hosting iOS push notifications with Web Push and PWAs","2026-03-25",{"_path":4,"title":8,"date":10},{"_path":1810,"title":1811,"date":1812},"/blog/welcome-to-my-blog","About this site","2024-01-15",1781294951014]