[{"data":1,"prerenderedAt":1293},["ShallowReactive",2],{"navigation":3,"$f1jvagmno7cfld":496,"\u002Fdocs\u002Fcomponents\u002Fmessage-scroller":507,"surround-\u002Fdocs\u002Fcomponents\u002Fmessage-scroller":1290},[4],{"title":5,"path":6,"stem":7,"children":8,"page":18},"Docs","\u002Fdocs","docs",[9,326,352,370,376,393,419,432],{"title":10,"path":11,"stem":12,"children":13,"new":18,"type":325},"Components","\u002Fdocs\u002Fcomponents","docs\u002F02.components",[14,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317,321],{"title":15,"path":16,"stem":17,"new":18,"type":19,"children":-1},"Accordion","\u002Fdocs\u002Fcomponents\u002Faccordion","docs\u002Fcomponents\u002Faccordion",false,"component",{"title":21,"path":22,"stem":23,"new":18,"type":19,"children":-1},"Alert","\u002Fdocs\u002Fcomponents\u002Falert","docs\u002Fcomponents\u002Falert",{"title":25,"path":26,"stem":27,"new":18,"type":19,"children":-1},"Alert Dialog","\u002Fdocs\u002Fcomponents\u002Falert-dialog","docs\u002Fcomponents\u002Falert-dialog",{"title":29,"path":30,"stem":31,"new":18,"type":19,"children":-1},"Aspect Ratio","\u002Fdocs\u002Fcomponents\u002Faspect-ratio","docs\u002Fcomponents\u002Faspect-ratio",{"title":33,"path":34,"stem":35,"new":18,"type":19,"children":-1},"Attachment","\u002Fdocs\u002Fcomponents\u002Fattachment","docs\u002Fcomponents\u002Fattachment",{"title":37,"path":38,"stem":39,"new":18,"type":19,"children":-1},"Avatar","\u002Fdocs\u002Fcomponents\u002Favatar","docs\u002Fcomponents\u002Favatar",{"title":41,"path":42,"stem":43,"new":18,"type":19,"children":-1},"Badge","\u002Fdocs\u002Fcomponents\u002Fbadge","docs\u002Fcomponents\u002Fbadge",{"title":45,"path":46,"stem":47,"new":18,"type":19,"children":-1},"Breadcrumb","\u002Fdocs\u002Fcomponents\u002Fbreadcrumb","docs\u002Fcomponents\u002Fbreadcrumb",{"title":49,"path":50,"stem":51,"new":18,"type":19,"children":-1},"Bubble","\u002Fdocs\u002Fcomponents\u002Fbubble","docs\u002Fcomponents\u002Fbubble",{"title":53,"path":54,"stem":55,"new":18,"type":19,"children":-1},"Button","\u002Fdocs\u002Fcomponents\u002Fbutton","docs\u002Fcomponents\u002Fbutton",{"title":57,"path":58,"stem":59,"new":18,"type":19,"children":-1},"Button Group","\u002Fdocs\u002Fcomponents\u002Fbutton-group","docs\u002Fcomponents\u002Fbutton-group",{"title":61,"path":62,"stem":63,"new":18,"type":19,"children":-1},"Calendar","\u002Fdocs\u002Fcomponents\u002Fcalendar","docs\u002Fcomponents\u002Fcalendar",{"title":65,"path":66,"stem":67,"new":18,"type":19,"children":-1},"Card","\u002Fdocs\u002Fcomponents\u002Fcard","docs\u002Fcomponents\u002Fcard",{"title":69,"path":70,"stem":71,"new":18,"type":19,"children":-1},"Carousel","\u002Fdocs\u002Fcomponents\u002Fcarousel","docs\u002Fcomponents\u002Fcarousel",{"title":73,"path":74,"stem":75,"new":18,"type":19,"children":-1},"Chart","\u002Fdocs\u002Fcomponents\u002Fchart","docs\u002Fcomponents\u002Fchart",{"title":77,"path":78,"stem":79,"new":18,"type":19,"children":-1},"Checkbox","\u002Fdocs\u002Fcomponents\u002Fcheckbox","docs\u002Fcomponents\u002Fcheckbox",{"title":81,"path":82,"stem":83,"new":18,"type":19,"children":-1},"Collapsible","\u002Fdocs\u002Fcomponents\u002Fcollapsible","docs\u002Fcomponents\u002Fcollapsible",{"title":85,"path":86,"stem":87,"new":18,"type":19,"children":-1},"ColorPicker","\u002Fdocs\u002Fcomponents\u002Fcolor-picker","docs\u002Fcomponents\u002Fcolor-picker",{"title":89,"path":90,"stem":91,"new":18,"type":19,"children":-1},"Combobox","\u002Fdocs\u002Fcomponents\u002Fcombobox","docs\u002Fcomponents\u002Fcombobox",{"title":93,"path":94,"stem":95,"new":18,"type":19,"children":-1},"Command","\u002Fdocs\u002Fcomponents\u002Fcommand","docs\u002Fcomponents\u002Fcommand",{"title":97,"path":98,"stem":99,"new":18,"type":19,"children":-1},"Context Menu","\u002Fdocs\u002Fcomponents\u002Fcontext-menu","docs\u002Fcomponents\u002Fcontext-menu",{"title":101,"path":102,"stem":103,"new":18,"type":19,"children":-1},"Curves","\u002Fdocs\u002Fcomponents\u002Fcurves","docs\u002Fcomponents\u002Fcurves",{"title":105,"path":106,"stem":107,"new":18,"type":19,"children":-1},"Data Table","\u002Fdocs\u002Fcomponents\u002Fdata-table","docs\u002Fcomponents\u002Fdata-table",{"title":109,"path":110,"stem":111,"new":18,"type":19,"children":-1},"Date Picker","\u002Fdocs\u002Fcomponents\u002Fdate-picker","docs\u002Fcomponents\u002Fdate-picker",{"title":113,"path":114,"stem":115,"new":18,"type":19,"children":-1},"Dialog","\u002Fdocs\u002Fcomponents\u002Fdialog","docs\u002Fcomponents\u002Fdialog",{"title":117,"path":118,"stem":119,"new":18,"type":19,"children":-1},"Drawer","\u002Fdocs\u002Fcomponents\u002Fdrawer","docs\u002Fcomponents\u002Fdrawer",{"title":121,"path":122,"stem":123,"new":18,"type":19,"children":-1},"Dropdown Menu","\u002Fdocs\u002Fcomponents\u002Fdropdown-menu","docs\u002Fcomponents\u002Fdropdown-menu",{"title":125,"path":126,"stem":127,"new":18,"type":19,"children":-1},"Empty","\u002Fdocs\u002Fcomponents\u002Fempty","docs\u002Fcomponents\u002Fempty",{"title":129,"path":130,"stem":131,"new":18,"type":19,"children":-1},"Field","\u002Fdocs\u002Fcomponents\u002Ffield","docs\u002Fcomponents\u002Ffield",{"title":133,"path":134,"stem":135,"new":18,"type":19,"children":-1},"FontPicker","\u002Fdocs\u002Fcomponents\u002Ffont-picker","docs\u002Fcomponents\u002Ffont-picker",{"title":137,"path":138,"stem":139,"new":18,"type":19,"children":-1},"Form","\u002Fdocs\u002Fcomponents\u002Fform","docs\u002Fcomponents\u002Fform",{"title":141,"path":142,"stem":143,"new":18,"type":19,"children":-1},"Gradient Picker","\u002Fdocs\u002Fcomponents\u002Fgradient-picker","docs\u002Fcomponents\u002Fgradient-picker",{"title":145,"path":146,"stem":147,"new":18,"type":19,"children":-1},"Hover Card","\u002Fdocs\u002Fcomponents\u002Fhover-card","docs\u002Fcomponents\u002Fhover-card",{"title":149,"path":150,"stem":151,"new":18,"type":19,"children":-1},"Input","\u002Fdocs\u002Fcomponents\u002Finput","docs\u002Fcomponents\u002Finput",{"title":153,"path":154,"stem":155,"new":18,"type":19,"children":-1},"Input Group","\u002Fdocs\u002Fcomponents\u002Finput-group","docs\u002Fcomponents\u002Finput-group",{"title":157,"path":158,"stem":159,"new":18,"type":19,"children":-1},"Input OTP","\u002Fdocs\u002Fcomponents\u002Finput-otp","docs\u002Fcomponents\u002Finput-otp",{"title":161,"path":162,"stem":163,"new":18,"type":19,"children":-1},"Item","\u002Fdocs\u002Fcomponents\u002Fitem","docs\u002Fcomponents\u002Fitem",{"title":165,"path":166,"stem":167,"new":18,"type":19,"children":-1},"Kbd","\u002Fdocs\u002Fcomponents\u002Fkbd","docs\u002Fcomponents\u002Fkbd",{"title":169,"path":170,"stem":171,"new":18,"type":19,"children":-1},"Label","\u002Fdocs\u002Fcomponents\u002Flabel","docs\u002Fcomponents\u002Flabel",{"title":173,"path":174,"stem":175,"new":18,"type":19,"children":-1},"Marker","\u002Fdocs\u002Fcomponents\u002Fmarker","docs\u002Fcomponents\u002Fmarker",{"title":177,"path":178,"stem":179,"new":18,"type":19,"children":-1},"Menubar","\u002Fdocs\u002Fcomponents\u002Fmenubar","docs\u002Fcomponents\u002Fmenubar",{"title":181,"path":182,"stem":183,"new":18,"type":19,"children":-1},"Message","\u002Fdocs\u002Fcomponents\u002Fmessage","docs\u002Fcomponents\u002Fmessage",{"title":185,"path":186,"stem":187,"new":18,"type":19,"children":-1},"Message Scroller","\u002Fdocs\u002Fcomponents\u002Fmessage-scroller","docs\u002Fcomponents\u002Fmessage-scroller",{"title":189,"path":190,"stem":191,"new":18,"type":19,"children":-1},"Native Select","\u002Fdocs\u002Fcomponents\u002Fnative-select","docs\u002Fcomponents\u002Fnative-select",{"title":193,"path":194,"stem":195,"new":18,"type":19,"children":-1},"Navigation Menu","\u002Fdocs\u002Fcomponents\u002Fnavigation-menu","docs\u002Fcomponents\u002Fnavigation-menu",{"title":197,"path":198,"stem":199,"new":18,"type":19,"children":-1},"Number Field","\u002Fdocs\u002Fcomponents\u002Fnumber-field","docs\u002Fcomponents\u002Fnumber-field",{"title":201,"path":202,"stem":203,"new":18,"type":19,"children":-1},"Pagination","\u002Fdocs\u002Fcomponents\u002Fpagination","docs\u002Fcomponents\u002Fpagination",{"title":205,"path":206,"stem":207,"new":18,"type":19,"children":-1},"Pin Input","\u002Fdocs\u002Fcomponents\u002Fpin-input","docs\u002Fcomponents\u002Fpin-input",{"title":209,"path":210,"stem":211,"new":18,"type":19,"children":-1},"Popover","\u002Fdocs\u002Fcomponents\u002Fpopover","docs\u002Fcomponents\u002Fpopover",{"title":213,"path":214,"stem":215,"new":18,"type":19,"children":-1},"Progress","\u002Fdocs\u002Fcomponents\u002Fprogress","docs\u002Fcomponents\u002Fprogress",{"title":217,"path":218,"stem":219,"new":220,"type":19,"children":-1},"Questionnaire","\u002Fdocs\u002Fcomponents\u002Fquestionnaire","docs\u002Fcomponents\u002Fquestionnaire",true,{"title":222,"path":223,"stem":224,"new":18,"type":19,"children":-1},"Radio Group","\u002Fdocs\u002Fcomponents\u002Fradio-group","docs\u002Fcomponents\u002Fradio-group",{"title":226,"path":227,"stem":228,"new":18,"type":19,"children":-1},"Range Calendar","\u002Fdocs\u002Fcomponents\u002Frange-calendar","docs\u002Fcomponents\u002Frange-calendar",{"title":230,"path":231,"stem":232,"new":18,"type":19,"children":-1},"Resizable","\u002Fdocs\u002Fcomponents\u002Fresizable","docs\u002Fcomponents\u002Fresizable",{"title":234,"path":235,"stem":236,"new":18,"type":19,"children":-1},"Scroll Area","\u002Fdocs\u002Fcomponents\u002Fscroll-area","docs\u002Fcomponents\u002Fscroll-area",{"title":238,"path":239,"stem":240,"new":18,"type":19,"children":-1},"Select","\u002Fdocs\u002Fcomponents\u002Fselect","docs\u002Fcomponents\u002Fselect",{"title":242,"path":243,"stem":244,"new":18,"type":19,"children":-1},"Separator","\u002Fdocs\u002Fcomponents\u002Fseparator","docs\u002Fcomponents\u002Fseparator",{"title":246,"path":247,"stem":248,"new":18,"type":19,"children":-1},"Sheet","\u002Fdocs\u002Fcomponents\u002Fsheet","docs\u002Fcomponents\u002Fsheet",{"title":250,"path":251,"stem":252,"new":18,"type":19,"children":-1},"Sidebar","\u002Fdocs\u002Fcomponents\u002Fsidebar","docs\u002Fcomponents\u002Fsidebar",{"title":254,"path":255,"stem":256,"new":18,"type":19,"children":-1},"Skeleton","\u002Fdocs\u002Fcomponents\u002Fskeleton","docs\u002Fcomponents\u002Fskeleton",{"title":258,"path":259,"stem":260,"new":18,"type":19,"children":-1},"Slider","\u002Fdocs\u002Fcomponents\u002Fslider","docs\u002Fcomponents\u002Fslider",{"title":262,"path":263,"stem":264,"new":18,"type":19,"children":-1},"Sonner","\u002Fdocs\u002Fcomponents\u002Fsonner","docs\u002Fcomponents\u002Fsonner",{"title":266,"path":267,"stem":268,"new":18,"type":19,"children":-1},"Spinner","\u002Fdocs\u002Fcomponents\u002Fspinner","docs\u002Fcomponents\u002Fspinner",{"title":270,"path":271,"stem":272,"new":18,"type":19,"children":-1},"Stepper","\u002Fdocs\u002Fcomponents\u002Fstepper","docs\u002Fcomponents\u002Fstepper",{"title":274,"path":275,"stem":276,"new":18,"type":19,"children":-1},"Switch","\u002Fdocs\u002Fcomponents\u002Fswitch","docs\u002Fcomponents\u002Fswitch",{"title":278,"path":279,"stem":280,"new":18,"type":19,"children":-1},"Table","\u002Fdocs\u002Fcomponents\u002Ftable","docs\u002Fcomponents\u002Ftable",{"title":282,"path":283,"stem":284,"new":18,"type":19,"children":-1},"Tabs","\u002Fdocs\u002Fcomponents\u002Ftabs","docs\u002Fcomponents\u002Ftabs",{"title":286,"path":287,"stem":288,"new":18,"type":19,"children":-1},"Tags Input","\u002Fdocs\u002Fcomponents\u002Ftags-input","docs\u002Fcomponents\u002Ftags-input",{"title":290,"path":291,"stem":292,"new":18,"type":19,"children":-1},"Textarea","\u002Fdocs\u002Fcomponents\u002Ftextarea","docs\u002Fcomponents\u002Ftextarea",{"title":294,"path":295,"stem":296,"new":18,"type":19,"children":-1},"Toast","\u002Fdocs\u002Fcomponents\u002Ftoast","docs\u002Fcomponents\u002Ftoast",{"title":298,"path":299,"stem":300,"new":18,"type":19,"children":-1},"Toggle","\u002Fdocs\u002Fcomponents\u002Ftoggle","docs\u002Fcomponents\u002Ftoggle",{"title":302,"path":303,"stem":304,"new":18,"type":19,"children":-1},"Toggle Group","\u002Fdocs\u002Fcomponents\u002Ftoggle-group","docs\u002Fcomponents\u002Ftoggle-group",{"title":306,"path":307,"stem":308,"new":18,"type":19,"children":-1},"Tool Rail","\u002Fdocs\u002Fcomponents\u002Ftool-rail","docs\u002Fcomponents\u002Ftool-rail",{"title":310,"path":311,"stem":312,"new":18,"type":19,"children":-1},"Tooltip","\u002Fdocs\u002Fcomponents\u002Ftooltip","docs\u002Fcomponents\u002Ftooltip",{"title":314,"path":315,"stem":316,"new":18,"type":19,"children":-1},"Tree","\u002Fdocs\u002Fcomponents\u002Ftree","docs\u002Fcomponents\u002Ftree",{"title":318,"path":319,"stem":320,"new":18,"type":19,"children":-1},"Typography","\u002Fdocs\u002Fcomponents\u002Ftypography","docs\u002Fcomponents\u002Ftypography",{"title":322,"path":323,"stem":324,"new":18,"type":19,"children":-1},"Vector Pad","\u002Fdocs\u002Fcomponents\u002Fvector-pad","docs\u002Fcomponents\u002Fvector-pad","group",{"title":327,"path":328,"stem":329,"children":330,"new":18,"type":325},"Installation","\u002Fdocs\u002Finstallation","docs\u002F02.installation",[331,336,340,344,348],{"title":332,"path":333,"stem":334,"new":18,"type":335,"children":-1},"Vite","\u002Fdocs\u002Finstallation\u002Fvite","docs\u002Finstallation\u002F01.vite","page",{"title":337,"path":338,"stem":339,"new":18,"type":335,"children":-1},"Nuxt","\u002Fdocs\u002Finstallation\u002Fnuxt","docs\u002Finstallation\u002F02.nuxt",{"title":341,"path":342,"stem":343,"new":18,"type":335,"children":-1},"Astro","\u002Fdocs\u002Finstallation\u002Fastro","docs\u002Finstallation\u002F03.astro",{"title":345,"path":346,"stem":347,"new":18,"type":335,"children":-1},"Laravel","\u002Fdocs\u002Finstallation\u002Flaravel","docs\u002Finstallation\u002F04.laravel",{"title":349,"path":350,"stem":351,"new":18,"type":335,"children":-1},"Manual Installation","\u002Fdocs\u002Finstallation\u002Fmanual","docs\u002Finstallation\u002F05.manual",{"title":353,"path":354,"stem":355,"children":356,"new":18,"type":325},"Dark Mode","\u002Fdocs\u002Fdark-mode","docs\u002F05.dark-mode",[357,360,363,367],{"title":332,"path":358,"stem":359,"new":18,"type":335,"children":-1},"\u002Fdocs\u002Fdark-mode\u002Fvite","docs\u002Fdark-mode\u002F01.vite",{"title":337,"path":361,"stem":362,"new":18,"type":335,"children":-1},"\u002Fdocs\u002Fdark-mode\u002Fnuxt","docs\u002Fdark-mode\u002F02.nuxt",{"title":364,"path":365,"stem":366,"new":18,"type":335,"children":-1},"Vitepress","\u002Fdocs\u002Fdark-mode\u002Fvitepress","docs\u002Fdark-mode\u002F03.vitepress",{"title":341,"path":368,"stem":369,"new":18,"type":335,"children":-1},"\u002Fdocs\u002Fdark-mode\u002Fastro","docs\u002Fdark-mode\u002F04.astro",{"title":371,"path":372,"stem":373,"children":374,"new":18,"type":325},"Directory","\u002Fdocs\u002Fdirectory","docs\u002Fdirectory\u002Findex",[375],{"title":371,"path":372,"stem":373,"new":18,"type":335,"children":-1},{"title":377,"path":378,"stem":379,"children":380,"new":18,"type":325},"Forms","\u002Fdocs\u002Fforms","docs\u002Fforms",[381,385,389],{"title":382,"path":383,"stem":384,"new":18,"type":335,"children":-1},"VeeValidate","\u002Fdocs\u002Fforms\u002Fvee-validate","docs\u002Fforms\u002F01.vee-validate",{"title":386,"path":387,"stem":388,"new":18,"type":335,"children":-1},"TanStack Form","\u002Fdocs\u002Fforms\u002Ftanstack-form","docs\u002Fforms\u002F02.tanstack-form",{"title":390,"path":391,"stem":392,"new":18,"type":335,"children":-1},"Formisch","\u002Fdocs\u002Fforms\u002Fformisch","docs\u002Fforms\u002F03.formisch",{"title":394,"path":395,"stem":396,"children":397,"new":18,"type":325},"Registry","\u002Fdocs\u002Fregistry","docs\u002Fregistry\u002Findex",[398,399,403,407,411,415],{"title":394,"path":395,"stem":396,"new":18,"type":335,"children":-1},{"title":400,"path":401,"stem":402,"new":18,"type":335,"children":-1},"Examples","\u002Fdocs\u002Fregistry\u002Fexamples","docs\u002Fregistry\u002Fexamples",{"title":404,"path":405,"stem":406,"new":18,"type":335,"children":-1},"FAQ","\u002Fdocs\u002Fregistry\u002Ffaq","docs\u002Fregistry\u002Ffaq",{"title":408,"path":409,"stem":410,"new":18,"type":335,"children":-1},"Getting Started","\u002Fdocs\u002Fregistry\u002Fgetting-started","docs\u002Fregistry\u002Fgetting-started",{"title":412,"path":413,"stem":414,"new":18,"type":335,"children":-1},"registry-item.json","\u002Fdocs\u002Fregistry\u002Fregistry-item-json","docs\u002Fregistry\u002Fregistry-item-json",{"title":416,"path":417,"stem":418,"new":18,"type":335,"children":-1},"registry.json","\u002Fdocs\u002Fregistry\u002Fregistry-json","docs\u002Fregistry\u002Fregistry-json",{"title":420,"path":421,"stem":422,"children":423,"page":18,"type":325},"Utilities","\u002Fdocs\u002Futilities","docs\u002Futilities",[424,428],{"title":425,"path":426,"stem":427,"new":18,"type":335,"children":-1},"scroll-fade","\u002Fdocs\u002Futilities\u002Fscroll-fade","docs\u002Futilities\u002Fscroll-fade",{"title":429,"path":430,"stem":431,"new":18,"type":335,"children":-1},"shimmer","\u002Fdocs\u002Futilities\u002Fshimmer","docs\u002Futilities\u002Fshimmer",{"path":6,"stem":7,"title":433,"type":325,"children":434},"Get Started",[435,439,446,450,454,460,464,468,472,476,480,484,488,492],{"title":436,"path":437,"stem":438,"new":18,"type":335,"children":-1},"Introduction","\u002Fdocs\u002Fintroduction","docs\u002F01.introduction",{"title":327,"path":328,"stem":329,"children":440,"new":18,"type":325},[441,442,443,444,445],{"title":332,"path":333,"stem":334,"new":18,"type":335,"children":-1},{"title":337,"path":338,"stem":339,"new":18,"type":335,"children":-1},{"title":341,"path":342,"stem":343,"new":18,"type":335,"children":-1},{"title":345,"path":346,"stem":347,"new":18,"type":335,"children":-1},{"title":349,"path":350,"stem":351,"new":18,"type":335,"children":-1},{"title":447,"path":448,"stem":449,"new":18,"type":335,"children":-1},"components.json","\u002Fdocs\u002Fcomponents-json","docs\u002F03.components-json",{"title":451,"path":452,"stem":453,"new":18,"type":335,"children":-1},"Theming","\u002Fdocs\u002Ftheming","docs\u002F04.theming",{"title":353,"path":354,"stem":355,"children":455,"new":18,"type":325},[456,457,458,459],{"title":332,"path":358,"stem":359,"new":18,"type":335,"children":-1},{"title":337,"path":361,"stem":362,"new":18,"type":335,"children":-1},{"title":364,"path":365,"stem":366,"new":18,"type":335,"children":-1},{"title":341,"path":368,"stem":369,"new":18,"type":335,"children":-1},{"title":461,"path":462,"stem":463,"new":18,"type":335,"children":-1},"CLI","\u002Fdocs\u002Fcli","docs\u002F06.cli",{"title":465,"path":466,"stem":467,"new":18,"type":335,"children":-1},"JavaScript","\u002Fdocs\u002Fjavascript","docs\u002F07.javascript",{"title":469,"path":470,"stem":471,"new":18,"type":335,"children":-1},"RTL","\u002Fdocs\u002Frtl","docs\u002F08.rtl",{"title":473,"path":474,"stem":475,"new":18,"type":335,"children":-1},"Figma","\u002Fdocs\u002Ffigma","docs\u002F09.figma",{"title":477,"path":478,"stem":479,"new":18,"type":335,"children":-1},"Changelog","\u002Fdocs\u002Fchangelog","docs\u002F10.changelog",{"title":481,"path":482,"stem":483,"new":18,"type":335,"children":-1},"Legacy Docs","\u002Fdocs\u002Flegacy","docs\u002F11.legacy",{"title":485,"path":486,"stem":487,"new":18,"type":335,"children":-1},"Skills","\u002Fdocs\u002Fskills","docs\u002Fskills",{"title":489,"path":490,"stem":491,"new":18,"type":335,"children":-1},"Typeset","\u002Fdocs\u002Ftypeset","docs\u002Ftypeset",{"title":420,"path":421,"stem":422,"children":493,"page":18,"type":325},[494,495],{"title":425,"path":426,"stem":427,"new":18,"type":335,"children":-1},{"title":429,"path":430,"stem":431,"new":18,"type":335,"children":-1},{"repo":497},{"id":498,"name":499,"repo":500,"description":501,"createdAt":502,"updatedAt":503,"pushedAt":504,"stars":505,"watchers":505,"forks":505,"defaultBranch":506},1338772706,"hui-vue","Clientik\u002Fhui-vue",null,"2026-08-18T19:33:07Z","2026-08-25T22:44:28Z","2026-08-25T22:44:11Z",0,"main",{"id":508,"title":185,"body":509,"description":1284,"extension":1285,"links":501,"meta":1286,"navigation":220,"new":18,"path":186,"rawbody":1287,"seo":1288,"stem":187,"__hash__":1289},"content\u002Fdocs\u002Fcomponents\u002Fmessage-scroller.md",{"type":510,"value":511,"toc":1257},"minimark",[512,520,525,533,541,544,599,603,612,615,619,627,631,636,648,654,657,661,665,668,672,676,683,687,691,701,705,709,716,720,724,735,739,743,753,757,761,772,778,782,786,801,805,809,815,819,823,826,837,959,962,996,1011,1015,1065,1069,1163,1178,1182,1187,1195,1224,1228,1234,1240,1244,1250],[513,514],"component-preview",{"className":515,"name":518,"previewClass":519},[516,517],"rounded-[34px]","sm:rounded-4xl","MessageScrollerDemo","h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16",[521,522,524],"h2",{"id":523},"messagescroller","MessageScroller",[526,527,528,529,532],"p",{},"A great streaming chat scroller has to juggle a lot at once: pin to the live edge while a reply streams, but never fight a reader who scrolls up; anchor each new turn near the top with a peek of the previous exchange; preserve position when older history loads above; and expose commands to jump anywhere in the thread. ",[530,531,524],"code",{}," owns those hard parts so your message list doesn't have to.",[526,534,535,536,540],{},"It does ",[537,538,539],"strong",{},"not"," own your messages, AI state, transport, or model — it is a headless scroll container you compose around your own rows.",[521,542,327],{"id":543},"installation",[545,546,547,562,575],"code-tabs",{},[548,549,550,556],"tabs-list",{},[551,552,554],"tabs-trigger",{"value":553},"cli",[526,555,461],{},[551,557,559],{"value":558},"manual",[526,560,561],{},"Manual",[563,564,565],"tabs-content",{"value":553},[566,567,573],"pre",{"className":568,"code":570,"language":571,"meta":572},[569],"language-bash","npx hui-kit@latest add message-scroller\n","bash","",[530,574,570],{"__ignoreMap":572},[563,576,577],{"value":558},[578,579,580,594],"steps",{},[581,582,583],"step",{},[526,584,585,586,593],{},"Copy and paste the ",[587,588,592],"a",{"href":589,"rel":590},"https:\u002F\u002Fgithub.com\u002FClientik\u002Fhui-vue\u002Ftree\u002Fdev\u002Fapps\u002Fv4\u002Fregistry\u002Fbases\u002Freka\u002Fui\u002Fmessage-scroller",[591],"nofollow","GitHub source code"," into your project.",[581,595,596],{},[526,597,598],{},"Update the import paths to match your project setup.",[521,600,602],{"id":601},"usage","Usage",[566,604,610],{"className":605,"code":607,"language":608,"meta":609},[606],"language-vue","\u003Cscript setup lang=\"ts\">\nimport {\n  MessageScroller,\n  MessageScrollerButton,\n  MessageScrollerContent,\n  MessageScrollerItem,\n  MessageScrollerProvider,\n  MessageScrollerViewport,\n} from '@\u002Fcomponents\u002Fui\u002Fmessage-scroller'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CMessageScrollerProvider auto-scroll default-scroll-position=\"last-anchor\">\n    \u003CMessageScroller>\n      \u003CMessageScrollerViewport>\n        \u003CMessageScrollerContent>\n          \u003CMessageScrollerItem\n            v-for=\"message in messages\"\n            :key=\"message.id\"\n            :message-id=\"message.id\"\n            :scroll-anchor=\"message.role === 'user'\"\n          >\n            \u003C!-- Message \u002F Bubble \u002F Marker goes here -->\n          \u003C\u002FMessageScrollerItem>\n        \u003C\u002FMessageScrollerContent>\n      \u003C\u002FMessageScrollerViewport>\n      \u003CMessageScrollerButton direction=\"end\" \u002F>\n    \u003C\u002FMessageScroller>\n  \u003C\u002FMessageScrollerProvider>\n\u003C\u002Ftemplate>\n","vue","showLineNumbers",[530,611,607],{"__ignoreMap":572},[526,613,614],{},"The provider must have a constrained height (or a height-bounded parent) so the viewport can scroll.",[521,616,618],{"id":617},"composition","Composition",[566,620,625],{"className":621,"code":623,"language":624,"meta":572},[622],"language-text","MessageScrollerProvider\n└── MessageScroller\n    ├── MessageScrollerViewport\n    │   └── MessageScrollerContent\n    │       └── MessageScrollerItem\n    └── MessageScrollerButton\n","text",[530,626,623],{"__ignoreMap":572},[521,628,630],{"id":629},"core-concepts","Core Concepts",[632,633,635],"h3",{"id":634},"anchoring-turns","Anchoring Turns",[526,637,638,639,643,644,647],{},"A turn is the part of the conversation that starts a new exchange — usually the user's message and the assistant reply that follows. An ",[640,641,642],"em",{},"anchor"," is the row the viewport should treat as the start of that turn. Mark that row with ",[530,645,646],{},"scrollAnchor",". When a new anchor is appended, the viewport moves it near the top and keeps a peek of the previous item above it, so the new turn does not feel detached from its context.",[566,649,652],{"className":650,"code":651,"language":608,"meta":572},[606],"\u003CMessageScrollerItem\n  :message-id=\"message.id\"\n  :scroll-anchor=\"message.role === 'user'\"\n>\n  \u003C!-- ... -->\n\u003C\u002FMessageScrollerItem>\n",[530,653,651],{"__ignoreMap":572},[526,655,656],{},"Scroll anchors are not tied to message role. You can turn any row into an anchor: a user message, a system marker, a handoff event, or anything else that starts a meaningful turn.",[513,658],{"className":659,"name":660,"previewClass":519},[516,517],"MessageScrollerAnchoringDemo",[632,662,664],{"id":663},"group-chat","Group Chat",[526,666,667],{},"In a group chat, the turn boundary is often the message that asks the model to respond, or a marker like \"Marcus joined the chat\". Typing indicators and history controls usually should not anchor. Because anchoring is role-independent, you can anchor a marker just as easily as a message.",[513,669],{"className":670,"name":671,"previewClass":519},[516,517],"MessageScrollerGroupChatDemo",[632,673,675],{"id":674},"keeping-context-visible","Keeping Context Visible",[526,677,678,679,682],{},"When a new turn starts, it should still feel like part of the same continuous thread. ",[530,680,681],{},"scrollPreviousItemPeek"," keeps a slice of the previous item visible above the anchor, so the reader keeps their context instead of feeling like the conversation restarted on a blank page.",[513,684],{"className":685,"name":686,"previewClass":519},[516,517],"MessageScrollerPreviousContextDemo",[632,688,690],{"id":689},"following-the-live-edge","Following the Live Edge",[526,692,693,694,697,698,700],{},"When the reader is at the live edge, ",[530,695,696],{},"autoScroll"," keeps streamed replies in view as they grow. Scrolling away from the live edge — by wheel, touch, keyboard, or dragging the scrollbar — releases the view, so new chunks arrive without moving the reader. ",[530,699,696],{}," composes with turn anchoring: when a new turn anchors near the top, the view stays put while the reply streams into the room below it.",[513,702],{"className":703,"name":704,"previewClass":519},[516,517],"MessageScrollerStreamingDemo",[632,706,708],{"id":707},"opening-saved-threads","Opening Saved Threads",[526,710,711,712,715],{},"Reopening a saved thread at the absolute end often drops the reader in without enough context. A better default is ",[530,713,714],{},"\"last-anchor\"",": show the last meaningful turn, like the user's latest message, with the reply below it.",[513,717],{"className":718,"name":719,"previewClass":519},[516,517],"MessageScrollerOpeningPositionDemo",[632,721,723],{"id":722},"loading-earlier-messages","Loading Earlier Messages",[526,725,726,727,730,731,734],{},"Loading earlier messages should not move the conversation the reader is already looking at. When older rows are prepended above the current transcript, ",[530,728,729],{},"MessageScrollerViewport"," preserves the visible row so the reader stays in the same place while history loads above them. This is enabled by default through ",[530,732,733],{},"preserveScrollOnPrepend",".",[513,736],{"className":737,"name":738,"previewClass":519},[516,517],"MessageScrollerLoadHistoryDemo",[632,740,742],{"id":741},"animating-new-messages","Animating New Messages",[526,744,745,746,749,750,752],{},"A common chat pattern is to animate the user's message when it is sent, then let the assistant reply stream into a regular row below it. Keep ",[530,747,748],{},"messageId"," and ",[530,751,646],{}," on the animated item and use transform and opacity for the entrance — avoid animating height, margin, or padding, which can fight the scroller's positioning.",[513,754],{"className":755,"name":756,"previewClass":519},[516,517],"MessageScrollerAnimationDemo",[632,758,760],{"id":759},"jumping-to-messages","Jumping to Messages",[526,762,763,764,767,768,771],{},"Search results, permalinks, outline items, and toolbar buttons often need to drive the transcript from outside the message list. Use ",[530,765,766],{},"useMessageScroller"," for those controls — the composables read from ",[530,769,770],{},"MessageScrollerProvider",", so they work in any component inside the provider.",[566,773,776],{"className":774,"code":775,"language":608,"meta":572},[606],"\u003Cscript setup lang=\"ts\">\nimport { useMessageScroller } from '@\u002Fcomponents\u002Fui\u002Fmessage-scroller'\n\nconst { scrollToMessage, scrollToEnd, scrollToStart } = useMessageScroller()\n\u003C\u002Fscript>\n",[530,777,775],{"__ignoreMap":572},[513,779],{"className":780,"name":781,"previewClass":519},[516,517],"MessageScrollerCommandsDemo",[632,783,785],{"id":784},"tracking-the-readers-position","Tracking the Reader's Position",[526,787,788,789,792,793,796,797,800],{},"Use ",[530,790,791],{},"useMessageScrollerVisibility"," to track the reader's position — a table-of-contents or jump menu that highlights the current anchored turn. ",[530,794,795],{},"currentAnchorId"," answers \"where am I\" and stays set after that anchor scrolls above the viewport; ",[530,798,799],{},"visibleMessageIds"," answers \"what is on screen\", in document order.",[513,802],{"className":803,"name":804,"previewClass":519},[516,517],"MessageScrollerVisibilityDemo",[632,806,808],{"id":807},"reading-scroll-state","Reading Scroll State",[526,810,788,811,814],{},[530,812,813],{},"useMessageScrollerScrollable"," when you need scroll state in JavaScript, such as a status indicator or a custom \"jump to latest\" control. It reports which edges the viewport can still scroll toward.",[513,816],{"className":817,"name":818,"previewClass":519},[516,517],"MessageScrollerScrollableDemo",[521,820,822],{"id":821},"api-reference","API Reference",[632,824,770],{"id":825},"messagescrollerprovider",[526,827,828,829,832,833,836],{},"Owns the scroll state and behavior. Provide it via ",[530,830,831],{},"provide","\u002F",[530,834,835],{},"inject"," and expose the scroll composables to descendants.",[838,839,840,859],"table",{},[841,842,843],"thead",{},[844,845,846,850,853,856],"tr",{},[847,848,849],"th",{},"Prop",[847,851,852],{},"Type",[847,854,855],{},"Default",[847,857,858],{},"Description",[860,861,862,882,902,922,940],"tbody",{},[844,863,864,869,874,879],{},[865,866,867],"td",{},[530,868,696],{},[865,870,871],{},[530,872,873],{},"boolean",[865,875,876],{},[530,877,878],{},"false",[865,880,881],{},"Follow the live edge while the reader is pinned to the bottom.",[844,883,884,889,894,899],{},[865,885,886],{},[530,887,888],{},"defaultScrollPosition",[865,890,891],{},[530,892,893],{},"'start' | 'end' | 'last-anchor'",[865,895,896],{},[530,897,898],{},"'end'",[865,900,901],{},"Opening position for the transcript.",[844,903,904,909,914,919],{},[865,905,906],{},[530,907,908],{},"scrollEdgeThreshold",[865,910,911],{},[530,912,913],{},"number",[865,915,916],{},[530,917,918],{},"8",[865,920,921],{},"Distance in px from an edge before it is considered scrollable.",[844,923,924,928,932,937],{},[865,925,926],{},[530,927,681],{},[865,929,930],{},[530,931,913],{},[865,933,934],{},[530,935,936],{},"64",[865,938,939],{},"Amount in px of the previous turn kept visible when anchoring.",[844,941,942,947,951,956],{},[865,943,944],{},[530,945,946],{},"scrollMargin",[865,948,949],{},[530,950,913],{},[865,952,953],{},[530,954,955],{},"0",[865,957,958],{},"Extra offset in px applied when scrolling to an element.",[632,960,729],{"id":961},"messagescrollerviewport",[838,963,964,976],{},[841,965,966],{},[844,967,968,970,972,974],{},[847,969,849],{},[847,971,852],{},[847,973,855],{},[847,975,858],{},[860,977,978],{},[844,979,980,984,988,993],{},[865,981,982],{},[530,983,733],{},[865,985,986],{},[530,987,873],{},[865,989,990],{},[530,991,992],{},"true",[865,994,995],{},"Keep the current view when messages are added above.",[526,997,998,999,1002,1003,1006,1007,1010],{},"Rendered as a ",[530,1000,1001],{},"role=\"region\"",", ",[530,1004,1005],{},"aria-label=\"Messages\"",", focusable (",[530,1008,1009],{},"tabindex=\"0\"",") native scroll container.",[632,1012,1014],{"id":1013},"messagescrolleritem","MessageScrollerItem",[838,1016,1017,1029],{},[841,1018,1019],{},[844,1020,1021,1023,1025,1027],{},[847,1022,849],{},[847,1024,852],{},[847,1026,855],{},[847,1028,858],{},[860,1030,1031,1048],{},[844,1032,1033,1037,1042,1045],{},[865,1034,1035],{},[530,1036,748],{},[865,1038,1039],{},[530,1040,1041],{},"string",[865,1043,1044],{},"—",[865,1046,1047],{},"Stable id used for anchoring, visibility, jumps.",[844,1049,1050,1054,1058,1062],{},[865,1051,1052],{},[530,1053,646],{},[865,1055,1056],{},[530,1057,873],{},[865,1059,1060],{},[530,1061,878],{},[865,1063,1064],{},"Marks this row as the start of a turn.",[632,1066,1068],{"id":1067},"messagescrollerbutton","MessageScrollerButton",[838,1070,1071,1083],{},[841,1072,1073],{},[844,1074,1075,1077,1079,1081],{},[847,1076,849],{},[847,1078,852],{},[847,1080,855],{},[847,1082,858],{},[860,1084,1085,1104,1124,1144],{},[844,1086,1087,1092,1097,1101],{},[865,1088,1089],{},[530,1090,1091],{},"direction",[865,1093,1094],{},[530,1095,1096],{},"'start' | 'end'",[865,1098,1099],{},[530,1100,898],{},[865,1102,1103],{},"Direction the button scrolls toward.",[844,1105,1106,1111,1116,1121],{},[865,1107,1108],{},[530,1109,1110],{},"behavior",[865,1112,1113],{},[530,1114,1115],{},"ScrollBehavior",[865,1117,1118],{},[530,1119,1120],{},"'smooth'",[865,1122,1123],{},"Scroll behavior for the jump.",[844,1125,1126,1131,1136,1141],{},[865,1127,1128],{},[530,1129,1130],{},"variant",[865,1132,1133],{},[530,1134,1135],{},"ButtonVariants",[865,1137,1138],{},[530,1139,1140],{},"'secondary'",[865,1142,1143],{},"Button variant.",[844,1145,1146,1151,1155,1160],{},[865,1147,1148],{},[530,1149,1150],{},"size",[865,1152,1153],{},[530,1154,1135],{},[865,1156,1157],{},[530,1158,1159],{},"'icon-sm'",[865,1161,1162],{},"Button size.",[526,1164,1165,1166,1169,1170,1173,1174,1177],{},"Exposes ",[530,1167,1168],{},"data-active"," for styling and becomes ",[530,1171,1172],{},"inert"," with ",[530,1175,1176],{},"tabindex=\"-1\""," when there is nothing to scroll toward.",[632,1179,1181],{"id":1180},"composables","Composables",[1183,1184,1186],"h4",{"id":1185},"usemessagescroller","useMessageScroller()",[566,1188,1193],{"className":1189,"code":1191,"language":1192,"meta":572},[1190],"language-ts","const { scrollToMessage, scrollToEnd, scrollToStart } = useMessageScroller()\n","ts",[530,1194,1191],{"__ignoreMap":572},[1196,1197,1198,1214],"ul",{},[1199,1200,1201,1204,1205,1207,1208,1210,1211,1213],"li",{},[530,1202,1203],{},"scrollToMessage(id, options?)"," — scroll to the item with the matching ",[530,1206,748],{},". Returns ",[530,1209,992],{}," if handled (queued if the item is not mounted yet), ",[530,1212,878],{}," if the id is missing after rows have mounted.",[1199,1215,1216,1219,1220,1223],{},[530,1217,1218],{},"scrollToEnd(options?)"," \u002F ",[530,1221,1222],{},"scrollToStart(options?)"," — scroll to the live edge or the top.",[1183,1225,1227],{"id":1226},"usemessagescrollervisibility","useMessageScrollerVisibility()",[566,1229,1232],{"className":1230,"code":1231,"language":1192,"meta":572},[1190],"const visibility = useMessageScrollerVisibility()\n\u002F\u002F visibility.value.currentAnchorId, visibility.value.visibleMessageIds\n",[530,1233,1231],{"__ignoreMap":572},[526,1235,1236,1237,1239],{},"Tracking only runs while something subscribes, and rows need a ",[530,1238,748],{}," to participate.",[1183,1241,1243],{"id":1242},"usemessagescrollerscrollable","useMessageScrollerScrollable()",[566,1245,1248],{"className":1246,"code":1247,"language":1192,"meta":572},[1190],"const scrollable = useMessageScrollerScrollable()\n\u002F\u002F scrollable.value.start, scrollable.value.end\n",[530,1249,1247],{"__ignoreMap":572},[526,1251,1252,1253,1256],{},"Reports which edges the viewport can still scroll toward. For styling the scroller itself, prefer the ",[530,1254,1255],{},"data-scrollable"," attribute.",{"title":572,"searchDepth":1258,"depth":1258,"links":1259},2,[1260,1261,1262,1263,1264,1277],{"id":523,"depth":1258,"text":524},{"id":543,"depth":1258,"text":327},{"id":601,"depth":1258,"text":602},{"id":617,"depth":1258,"text":618},{"id":629,"depth":1258,"text":630,"children":1265},[1266,1268,1269,1270,1271,1272,1273,1274,1275,1276],{"id":634,"depth":1267,"text":635},3,{"id":663,"depth":1267,"text":664},{"id":674,"depth":1267,"text":675},{"id":689,"depth":1267,"text":690},{"id":707,"depth":1267,"text":708},{"id":722,"depth":1267,"text":723},{"id":741,"depth":1267,"text":742},{"id":759,"depth":1267,"text":760},{"id":784,"depth":1267,"text":785},{"id":807,"depth":1267,"text":808},{"id":821,"depth":1258,"text":822,"children":1278},[1279,1280,1281,1282,1283],{"id":825,"depth":1267,"text":770},{"id":961,"depth":1267,"text":729},{"id":1013,"depth":1267,"text":1014},{"id":1067,"depth":1267,"text":1068},{"id":1180,"depth":1267,"text":1181},"A scroll container for chat transcripts that anchors turns, follows streamed replies, restores prepended history, and jumps to messages.","md",{"component":220},"---\ntitle: Message Scroller\ndescription: A scroll container for chat transcripts that anchors turns, follows streamed replies, restores prepended history, and jumps to messages.\ncomponent: true\n---\n\n::component-preview\n---\nname: MessageScrollerDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n## MessageScroller\n\nA great streaming chat scroller has to juggle a lot at once: pin to the live edge while a reply streams, but never fight a reader who scrolls up; anchor each new turn near the top with a peek of the previous exchange; preserve position when older history loads above; and expose commands to jump anywhere in the thread. `MessageScroller` owns those hard parts so your message list doesn't have to.\n\nIt does **not** own your messages, AI state, transport, or model — it is a headless scroll container you compose around your own rows.\n\n## Installation\n\n:::::code-tabs\n\n:::tabs-list\n\n  ::tabs-trigger{value=\"cli\"}\n  CLI\n  ::\n\n  ::tabs-trigger{value=\"manual\"}\n  Manual\n  ::\n\n:::\n\n::tabs-content{value=\"cli\"}\n\n```bash\nnpx hui-kit@latest add message-scroller\n```\n\n::\n\n::::tabs-content{value=\"manual\"}\n  :::steps\n    ::step\n    Copy and paste the [GitHub source code](https:\u002F\u002Fgithub.com\u002FClientik\u002Fhui-vue\u002Ftree\u002Fdev\u002Fapps\u002Fv4\u002Fregistry\u002Fbases\u002Freka\u002Fui\u002Fmessage-scroller) into your project.\n    ::\n\n    ::step\n    Update the import paths to match your project setup.\n    ::\n  :::\n::::\n\n:::::\n\n## Usage\n\n```vue showLineNumbers\n\u003Cscript setup lang=\"ts\">\nimport {\n  MessageScroller,\n  MessageScrollerButton,\n  MessageScrollerContent,\n  MessageScrollerItem,\n  MessageScrollerProvider,\n  MessageScrollerViewport,\n} from '@\u002Fcomponents\u002Fui\u002Fmessage-scroller'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CMessageScrollerProvider auto-scroll default-scroll-position=\"last-anchor\">\n    \u003CMessageScroller>\n      \u003CMessageScrollerViewport>\n        \u003CMessageScrollerContent>\n          \u003CMessageScrollerItem\n            v-for=\"message in messages\"\n            :key=\"message.id\"\n            :message-id=\"message.id\"\n            :scroll-anchor=\"message.role === 'user'\"\n          >\n            \u003C!-- Message \u002F Bubble \u002F Marker goes here -->\n          \u003C\u002FMessageScrollerItem>\n        \u003C\u002FMessageScrollerContent>\n      \u003C\u002FMessageScrollerViewport>\n      \u003CMessageScrollerButton direction=\"end\" \u002F>\n    \u003C\u002FMessageScroller>\n  \u003C\u002FMessageScrollerProvider>\n\u003C\u002Ftemplate>\n```\n\nThe provider must have a constrained height (or a height-bounded parent) so the viewport can scroll.\n\n## Composition\n\n```text\nMessageScrollerProvider\n└── MessageScroller\n    ├── MessageScrollerViewport\n    │   └── MessageScrollerContent\n    │       └── MessageScrollerItem\n    └── MessageScrollerButton\n```\n\n## Core Concepts\n\n### Anchoring Turns\n\nA turn is the part of the conversation that starts a new exchange — usually the user's message and the assistant reply that follows. An *anchor* is the row the viewport should treat as the start of that turn. Mark that row with `scrollAnchor`. When a new anchor is appended, the viewport moves it near the top and keeps a peek of the previous item above it, so the new turn does not feel detached from its context.\n\n```vue\n\u003CMessageScrollerItem\n  :message-id=\"message.id\"\n  :scroll-anchor=\"message.role === 'user'\"\n>\n  \u003C!-- ... -->\n\u003C\u002FMessageScrollerItem>\n```\n\nScroll anchors are not tied to message role. You can turn any row into an anchor: a user message, a system marker, a handoff event, or anything else that starts a meaningful turn.\n\n::component-preview\n---\nname: MessageScrollerAnchoringDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Group Chat\n\nIn a group chat, the turn boundary is often the message that asks the model to respond, or a marker like \"Marcus joined the chat\". Typing indicators and history controls usually should not anchor. Because anchoring is role-independent, you can anchor a marker just as easily as a message.\n\n::component-preview\n---\nname: MessageScrollerGroupChatDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Keeping Context Visible\n\nWhen a new turn starts, it should still feel like part of the same continuous thread. `scrollPreviousItemPeek` keeps a slice of the previous item visible above the anchor, so the reader keeps their context instead of feeling like the conversation restarted on a blank page.\n\n::component-preview\n---\nname: MessageScrollerPreviousContextDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Following the Live Edge\n\nWhen the reader is at the live edge, `autoScroll` keeps streamed replies in view as they grow. Scrolling away from the live edge — by wheel, touch, keyboard, or dragging the scrollbar — releases the view, so new chunks arrive without moving the reader. `autoScroll` composes with turn anchoring: when a new turn anchors near the top, the view stays put while the reply streams into the room below it.\n\n::component-preview\n---\nname: MessageScrollerStreamingDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Opening Saved Threads\n\nReopening a saved thread at the absolute end often drops the reader in without enough context. A better default is `\"last-anchor\"`: show the last meaningful turn, like the user's latest message, with the reply below it.\n\n::component-preview\n---\nname: MessageScrollerOpeningPositionDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Loading Earlier Messages\n\nLoading earlier messages should not move the conversation the reader is already looking at. When older rows are prepended above the current transcript, `MessageScrollerViewport` preserves the visible row so the reader stays in the same place while history loads above them. This is enabled by default through `preserveScrollOnPrepend`.\n\n::component-preview\n---\nname: MessageScrollerLoadHistoryDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Animating New Messages\n\nA common chat pattern is to animate the user's message when it is sent, then let the assistant reply stream into a regular row below it. Keep `messageId` and `scrollAnchor` on the animated item and use transform and opacity for the entrance — avoid animating height, margin, or padding, which can fight the scroller's positioning.\n\n::component-preview\n---\nname: MessageScrollerAnimationDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Jumping to Messages\n\nSearch results, permalinks, outline items, and toolbar buttons often need to drive the transcript from outside the message list. Use `useMessageScroller` for those controls — the composables read from `MessageScrollerProvider`, so they work in any component inside the provider.\n\n```vue\n\u003Cscript setup lang=\"ts\">\nimport { useMessageScroller } from '@\u002Fcomponents\u002Fui\u002Fmessage-scroller'\n\nconst { scrollToMessage, scrollToEnd, scrollToStart } = useMessageScroller()\n\u003C\u002Fscript>\n```\n\n::component-preview\n---\nname: MessageScrollerCommandsDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Tracking the Reader's Position\n\nUse `useMessageScrollerVisibility` to track the reader's position — a table-of-contents or jump menu that highlights the current anchored turn. `currentAnchorId` answers \"where am I\" and stays set after that anchor scrolls above the viewport; `visibleMessageIds` answers \"what is on screen\", in document order.\n\n::component-preview\n---\nname: MessageScrollerVisibilityDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n### Reading Scroll State\n\nUse `useMessageScrollerScrollable` when you need scroll state in JavaScript, such as a status indicator or a custom \"jump to latest\" control. It reports which edges the viewport can still scroll toward.\n\n::component-preview\n---\nname: MessageScrollerScrollableDemo\nclass: \"rounded-[34px] sm:rounded-4xl\"\npreviewClass: h-auto theme-green bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16\n---\n::\n\n## API Reference\n\n### MessageScrollerProvider\n\nOwns the scroll state and behavior. Provide it via `provide`\u002F`inject` and expose the scroll composables to descendants.\n\n| Prop                     | Type                                  | Default        | Description                                                            |\n| ------------------------ | ------------------------------------- | -------------- | -------------------------------------------------------------------- |\n| `autoScroll`             | `boolean`                             | `false`        | Follow the live edge while the reader is pinned to the bottom.        |\n| `defaultScrollPosition`  | `'start' \\| 'end' \\| 'last-anchor'`   | `'end'`        | Opening position for the transcript.                                  |\n| `scrollEdgeThreshold`    | `number`                              | `8`            | Distance in px from an edge before it is considered scrollable.       |\n| `scrollPreviousItemPeek` | `number`                              | `64`           | Amount in px of the previous turn kept visible when anchoring.        |\n| `scrollMargin`           | `number`                              | `0`            | Extra offset in px applied when scrolling to an element.              |\n\n### MessageScrollerViewport\n\n| Prop                       | Type      | Default | Description                                             |\n| -------------------------- | --------- | ------- | ------------------------------------------------------- |\n| `preserveScrollOnPrepend`  | `boolean` | `true`  | Keep the current view when messages are added above.    |\n\nRendered as a `role=\"region\"`, `aria-label=\"Messages\"`, focusable (`tabindex=\"0\"`) native scroll container.\n\n### MessageScrollerItem\n\n| Prop           | Type      | Default | Description                                      |\n| -------------- | --------- | ------- | ------------------------------------------------ |\n| `messageId`    | `string`  | —       | Stable id used for anchoring, visibility, jumps. |\n| `scrollAnchor` | `boolean` | `false` | Marks this row as the start of a turn.           |\n\n### MessageScrollerButton\n\n| Prop        | Type                  | Default   | Description                              |\n| ----------- | --------------------- | --------- | ---------------------------------------- |\n| `direction` | `'start' \\| 'end'`    | `'end'`   | Direction the button scrolls toward.     |\n| `behavior`  | `ScrollBehavior`      | `'smooth'`| Scroll behavior for the jump.            |\n| `variant`   | `ButtonVariants`      | `'secondary'` | Button variant.                      |\n| `size`      | `ButtonVariants`      | `'icon-sm'`   | Button size.                         |\n\nExposes `data-active` for styling and becomes `inert` with `tabindex=\"-1\"` when there is nothing to scroll toward.\n\n### Composables\n\n#### useMessageScroller()\n\n```ts\nconst { scrollToMessage, scrollToEnd, scrollToStart } = useMessageScroller()\n```\n\n- `scrollToMessage(id, options?)` — scroll to the item with the matching `messageId`. Returns `true` if handled (queued if the item is not mounted yet), `false` if the id is missing after rows have mounted.\n- `scrollToEnd(options?)` \u002F `scrollToStart(options?)` — scroll to the live edge or the top.\n\n#### useMessageScrollerVisibility()\n\n```ts\nconst visibility = useMessageScrollerVisibility()\n\u002F\u002F visibility.value.currentAnchorId, visibility.value.visibleMessageIds\n```\n\nTracking only runs while something subscribes, and rows need a `messageId` to participate.\n\n#### useMessageScrollerScrollable()\n\n```ts\nconst scrollable = useMessageScrollerScrollable()\n\u002F\u002F scrollable.value.start, scrollable.value.end\n```\n\nReports which edges the viewport can still scroll toward. For styling the scroller itself, prefer the `data-scrollable` attribute.\n",{"title":185,"description":1284},"wH69zOOmgY3cv1-qG_oPBNEM8VmzewX7pevgDdC-Od4",[1291,1292],{"title":181,"path":182,"stem":183,"children":-1},{"title":189,"path":190,"stem":191,"children":-1},1787698063259]