Repository navigation
v0.4.0
A review of all 35 components: smaller downloads (the bundle every page loads is 22% smaller), about a hundred bugs fixed, form participation for the form-like components, and browser tests for the value contract, forms and shrinking.
Changed
- Component modules are shrunk before they are minified: the
.docs()text, themanifest:block passed torocket(), and comments and needless whitespace in CSS and HTML templates no longer ship. Modules are 18% smaller and the bundle 16%. Every component gets a new version once (the shrinking is part of the version hash), so pinned URLs keep working and the new files replace nothing.manifest.jsonis now published from the readable modules. sb-code-editorloads Prism only when an editor highlights, so the bundle every page loads is 7.2 kB smaller; code shows uncoloured until it arrives. Prism is rebuilt from its language components (0.9 kB less, identical highlighting).- Size tables and the playground's size line no longer count a component as its own dependency (
sb-dropdownshowed 15.8 kB "with deps" for a 7.9 kB module) or a file only the docs' examples load (sb-autoloader'sdemo-badge.js). - Altogether,
/c/bundle.jsshrinks from 67.1 kB to 52.7 kB (brotli) and the catalog's modules from 86.2 kB to 75.1 kB, while fixing everything below and adding form participation. - The server can clear a value it never set:
value=""(orvalue="0",checked="false",open="false") sent to an element rendered without that attribute now wins insb-code-editor,sb-dropdown,sb-input,sb-radio-group,sb-rating,sb-select,sb-slider,sb-toggleandsb-tree; Rocket used to ignore it, since the decoded value didn't change. A removed attribute is still ignored, and a browser test checks both for every value component. - Forced colours (Windows High Contrast): focus rings, carets, checks, tracks, icons, status lights and the chosen item stay visible in
sb-alert,sb-busy,sb-button,sb-card,sb-code-playground,sb-copy-button,sb-details,sb-dropdown,sb-input,sb-meter,sb-pixel-board,sb-radio-group,sb-select,sb-slider,sb-tabs,sb-theme-switchandsb-toggle. Some of them used to vanish. - The
hiddenattribute hides every component, also on pages without a[hidden]reset: most set their owndisplay, which beat the browser's rule. disabled="false"(whatel.disabled = falsewrites) no longer dims a component or blocks its clicks:sb-button(andloading="false"),sb-dropdown,sb-radio-group,sb-rating,sb-select,sb-sliderandsb-toggle.- Right-to-left pages: fills, carets, focus bars, close buttons, tips and arrow keys follow the reading direction in
sb-alert,sb-busy,sb-copy-button,sb-details,sb-dropdown,sb-input,sb-odometer,sb-radio-group,sb-range,sb-rating,sb-select,sb-slider,sb-tabs,sb-theme-switch,sb-toast,sb-toggleandsb-tooltip. For example,sb-ratingfills half units from the start side,sb-tooltipcentres top and bottom tips on the trigger, andsb-odometerkeeps its digits in left-to-right order. - Canvas components follow every theme change:
sb-gaugeandsb-sparklinerepaint whenever a colour token changes, from any cause (a theme scoped to a container, a class,light-dark(), forced colours), not only on a theme-switch pick. A stillsb-nebulaorsb-starfield(speed 0 or reduced motion) repaints on a theme change or when the system turns light or dark, andsb-echarts' pie and funnel labels follow the theme too. - A removed
sb-echarts,sb-gaugeorsb-sparklineno longer throws on every later theme change: their window listeners outlived the element. - An invalid
lang(en_US,de_DE, a stray space) no longer blankssb-count-up,sb-echarts,sb-odometerorsb-relative-time: an underscore is read as a hyphen (de_DEis German), and other invalid tags fall back to the browser's locale. The first three also find the page'slangfrom inside another component's shadow root, andsb-echartsfollows a changedlang. - A token's fallback (what a component uses on a page without Starbase's tokens) is the same in every component, and a test keeps it so:
--sb-surface-raisedinsb-dropdownandsb-toast,--sb-surface-hoverinsb-button,--sb-dangerinsb-copy-buttonand--sb-radius-sm(6px) insb-treehad their own. - Form-like components take part in the
<form>they sit in:sb-code-editor,sb-input,sb-radio-group,sb-range,sb-rating,sb-select,sb-sliderandsb-togglesubmit their value under theirnamethe way their native counterparts do (a toggle sendsname=ononly when on, a multiple select one entry per pick, a radio group nothing until a choice is picked, a range its{start, end}JSON), so native submits,new FormData(form)and Datastar'scontentType: 'form'include them, and a form reset brings back the server's value (a reset the page cancels leaves them alone). They are not form-associated elements yet, because Rocket can't declare one, so validity,<fieldset disabled>,<label for>and theformattribute don't reach them; each README's Forms section says what works.sb-inputandsb-code-editorget adisabledprop.sb-treestays commands-only, andsb-buttonneither submits nor resets a form. sb-tabsemitsinputon every move, andchange,sb-changeandsb-tab-changeonly on commit (the last two fired on every arrow key).sb-change's detail now carries the tab'slabel. A click commits at once, the arrow keys, Home and End after a 250 ms pause, so running through the tabs sends one command instead of one per tab.sb-inputtakesrev: when it changes, the server's value wins even if it is the same, so a command the server normalises back to the stored value (or ignores) no longer leaves the field pending. The Showcase call sign uses it.sb-busyno longer setsaria-busyon itself: on an ancestor of its status region it could hold the announcement back, and a morph stripped it. Set it on the content that is loading;:state(busy)stays the styling hook.sb-modalignores a removedopenattribute, like the other server-driven attributes: to close, the server sendsopen="false". Inline panels no longer show a close button that did nothing, the close button is partclose, and the corners follow the theme's--sb-radius.sb-meter's default warn and danger thresholds are 70% and 90% of itsmin–maxrange instead of the absolute values 70 and 90 (the same on 0–100). Its tone is:state(ok|warn|danger), and its blocks are partsegment, lit ones alsolit.sb-dropdown'smenupart (withrole="menu") is now the panel inside each level's popover, which casts the drop shadow. Its Styling docs set tokens on the element, since a token set on::part(menu)never reached the panel.sb-toastidentifies a toast without anidby its message (#2,#3… for repeats), which is the idsb-dismissreports, so dismissing the first plain-string toast no longer hides the next one.sb-dismissfires after the toast is hidden locally.- New hooks:
sb-alerthas aniconslot (in place of the status light) and:state(closed), andhost.openreads and sets whether it shows;sb-qr-code's "Too much data" is anerrorslot in anerrorpart, to translate and restyle it;sb-sparklineandsb-starfieldtake alabelfor their accessible name (label=""makes a starfield decoration);sb-range's thumbs follow--sb-slider-thumband--sb-slider-thumb-edge, likesb-slider's;sb-tooltipstacks at--sb-z-tooltip(default 70).
Fixed
sb-alertcomes back when the server changes itsopenattribute after a dismissal (unchanged markup keeps the dismissal), and a closed alert no longer leaves an empty gap in a grid or flex stack. Headings meet WCAG AA contrast on light themes, and long URLs wrap instead of pushing the close button out of the box.sb-autoloader'ssb-readyandel.readywait until every component on the page at startup has loaded or failed (they fired at the timeout, with a wrongloadedcount;timeoutnow only lifts the cloak), once per loader, also after a morph moves it. A module that doesn't define its tag is reported (sb-load-error) instead of blocking that tag for good, a failed module is fetched again when its tag reappears, andel.load(tag)andel.discover(root)return promises.sb-busyno longer stays up forever when the element that fired a request is replaced or removed before the response (a Delete button whose row the response removes). Its label is announced when a wait starts, and one removed while up emits a lastsb-busy-change { busy: false }.sb-buttonno longer traps the keyboard while loading (Tab, Escape and page shortcuts work; clicks, Enter and Space stay blocked). A disabled button ignores clicks,el.click()included, and they no longer reach the element behind it.aria-labelreaches the inner button or link, so icon-only buttons have a name, and slotted icons no longer shrink to nothing.sb-cardhas a width of its own in flex rows,autogrid columns and fit-content layouts (it collapsed to 0 px), keeps inline markup in the flow of the text (block children now flow like a<div>, with their own margins), and collapses an empty body. It no longer clips tooltips that reach outside it or makes photos jagged, and in a linked card, footer actions and body links and buttons get their own clicks, and keyboard focus rings the whole card.sb-code-editor: Shift+Tab without a selection no longer selects the start of the line (the next keystroke deleted it), and Enter or Tab that confirm IME input are left to the IME. Code from a child<script type="text/plain">is the server's value (confirmis no longer pending on load, andrevert()no longer empties the editor), edits survive a move, and the gutter keeps its width when a line overflows, so the code no longer jumps sideways while typing.sb-code-playground: an endless loop no longer kills the preview (on a page with several playgrounds, every preview); the runner stops it after a second and names the line. Runs no longer add browser history, 2000console.loglines settle in well under a second instead of about 10 s, a fresh console no longer shows the previous run's lines, the editors'changeandsb-changeno longer escape, and the file tabs work with the keyboard.sb-copy-buttonre-renders only whenlabelchanges, not on every newvalue(a bound value can change on every keystroke), stays quiet when it is removed during a pending clipboard write, and its hover edge no longer fades on light themes.sb-count-upno longer counts again fromfromwhen it is moved, prints and saves to PDF with its final value instead of 0, and keeps room for its final value, so the text around it stays put while it counts.sb-detailskeeps its open state when app code moves it, like a native<details>, and panels in onegroupare exclusive from the first paint. Whereinterpolate-sizeis unsupported it opens and closes at once instead of stalling and then snapping.sb-dropdown: clicking a parent whose submenu opened on hover (or pressing Enter on it) keeps the submenu open and moves the focus into it, the focus follows the pointer so Enter chooses the row under it, type-ahead keeps the whole word and cycles on a repeated letter, and the drop shadow shows. A menu moved or removed while open sendssb-close { reason: "api" }.sb-echarts:defineChartKindandsetNumberFormatwork from any copy of the module (the README recipe failed with every install method), the unversioned/c/echarts/route serves the vendored ECharts file the readable module imports, and a chart whose kind isn't defined yet shows its fallback until it is. Axis tooltips show each series' own value for dataset options, the default legend and a sliderdataZoomno longer cover the x-axis labels, resizing no longer breaks multi-grid layouts, polar, calendar and geo charts lose their phantom axes, and an option ECharts can't draw no longer blocks every later one. Charts without a fallback can be used from the keyboard: the arrow keys step through items with their tooltips, and Enter firessb-chart-click.sb-gaugestops animating offscreen (live gauges repainted at 60 fps after you scrolled away), follows newminandmaxat once witharia-valuenowkept in range, and lights the bottom row at both ends of its arc.sb-input: Enter commits the value (changeandsb-change), so a command runs on Enter and not only on blur, but not the Enter that confirms an input-method word. A new server value,revert()or a property write re-checks the field (a stale error stayed up), and a move keeps unsaved text with its pending and error state. Only the label names the field; the hint and the error describe it, and errors are announced politely.sb-meter's cascade starts at the edge that moves, so a long bar no longer lags and a falling or fast-changing one leaves no lit blocks behind; any value aboveminlights a block, and onlymaxlights them all. It is the meter itself for assistive technology, named by a hostaria-label, and its label and number are no longer read twice.sb-modalno longer turns into an invisible modal that blocks the whole page when the server opens it after the first render or a prop changes while it is open, and switchinginlineat runtime no longer crashes. Adata-sb-closebutton in a nested modal closes only its own dialog, a text selection released over the backdrop no longer closes it, and the server can close a dialog opened withshow().sb-nebulastays alive when it is moved in the DOM (it went blank for good), no longer flashes black while resized, and shows its still glow after losing its WebGL context. Any seed gives a sky (seeds wrap at 101; 0 to 100 are unchanged), light themes keep a dark sky instead of black blotches, andlabel=""makes it decoration.sb-odometer: below zero the wheels turn the way the digits count (−15 → −13 rolls back two instead of on through eight), a value that arrives mid-turn rolls on from where the wheel is instead of jumping, copying a selection copies the value instead of every wheel's digits, anddrum="false"draws flat wheels.sb-pixel-boardkeeps working, drawing included, after a morph or re-attach (removing it threw, and so did every later paint). It paints only with the primary button of one pointer (a right click painted, and two fingers drew a line), sends at most 60 cells persb-paint, lets a finger scroll the page over areadonlyboard, and its palette is one tab stop. The README's example usesrequestCancellation: 'disabled', so a copy no longer drops pixels mid-stroke.sb-qr-codewithaccentcaps the corner squares' lightness, so codes scan on themes with a light brand colour (Terminal's green decoded in 0 of 8 tries). Text with a lone surrogate (cut mid-emoji) encodes instead of showing "Too much data", and a fractionalborderis rounded to whole modules instead of clipping the code.sb-radio-groupno longer takes the focus back (and scrolls the page to itself) after a click elsewhere, and its disabled choices can no longer take the tab stop from a click. It is the radiogroup itself, so a page'saria-labeloraria-labelledbynames it, and arrow keys with Alt, Ctrl or Meta are left to the browser.sb-range's track and fill no longer disappear after a prop change or a confirmed command. Values snap tosteplike the thumbs, a server update ofmin/maxwithvaluekeeps the server's range in either attribute order, anullstart or end meansmin/max(it collapsed to 0), thumbs that meet can be dragged apart either way, and the focused thumb shows a ring.sb-ratingwithclearableno longer clears when an arrow key or End is pressed at the maximum, and a change shows at once while the pointer rests on the row. On touch a vertical swipe scrolls the page and a drag along the row picks a value, a server update that raisesmaxwithvaluekeeps the value, and areadonlyrating announces its value ("4.5 of 5").sb-relative-timeno longer goes stale on future times ("in 1 hour" stayed until only half an hour was left), counts days by calendar date in the viewer's time zone (so "yesterday" is the date before today), switches atthresholdin both directions, says "1 year ago" from about 350 days, and readsdatetime="2026"as a year, not Unix seconds.sb-select: a disabled select is out of the tab order and ignores keys, an empty one shows no clear button, and reading its value no longer makes it pending. A remote select no longer lists old results under "Type to search" or spins forever when an answer changes nothing. Withoutsearchableorremoteit opens and picks with Space and jumps to typed letters, its status messages are announced, and removing a focused select no longer throws.sb-sliderno longer loses its track after a re-render (a server echo, a change tounit,disabledorticks), and withconfirma held arrow key no longer loses steps to older echoes. It has an accessible name (labeloraria-label), its value text and fill followunit,step,minandmax, and server values snap tosteplike the thumb.sb-sparkline's height no longer depends onlength(the line is--sb-sparkline-heighttall, 2.25rem by default, with square pixels), its area sits under the stepped line, and togglingshow-valueno longer blanks it. Push mode ignores a removed or re-sentvalue, keeps its history across a move, and trims whenlengthshrinks.sb-starfield's still frame (speed 0 or reduced motion) shows every star and no longer adds stars on each repaint, and it no longer blanks while it is resized.sb-tabsshows its focus ring on the selected tab, and aselectedpast the last tab selects the last one (none was selected, which took the tab list out of the tab order).el.selectedis the live index and a write no longer reflects to the attribute (a morph reset it), sodata-bindworks. Panel slots keep letters and digits in any script, the strip no longer overflows its container by 10 px, and the host'saria-labelnames the tab list.sb-theme-switch: removing or moving a switch no longer throws, the menu's arrow keys apply each theme without closing it, and focus goes back to the button. A switch whose list lacks the saved theme no longer resets the page to auto, it follows laterthemesandlabelschanges, and the menu opens centred instead of in the top-left corner in browsers without anchor positioning.sb-toast's countdown bar shows the real remaining time, new toasts enter at top placements and when the stack is full, and a dismissed toast fades out even when the page drops it at once. Dismissing with the mouse no longer pauses every other countdown, keyboard focus stays with its toast as the stack changes,clear()also dismisses toasts waiting behindmax, and the drop shadow shows.sb-toggle's label takes the colour of the text around it (it was unreadable on light pages without Starbase's tokens), an on toggle's knob uses--sb-text-on-brandand stays readable on the brand track (Terminal: 1.28:1 → 12.46:1),aria-labelnames the switch, and a moved toggle keeps its state and pending mark.sb-tooltip's hidden tips are no longer read as stray text, and a shown tip is announced. Escape dismisses it wherever the focus is, the pointer passing over a focused trigger no longer hides its tip, and a shown tip takes the pointer, so it can be hovered (WCAG 1.4.13) and covers what is under it. A tooltip without content no longer shows an empty box.sb-treeno longer takes the focus back (and scrolls the page to itself) when the server updates it after a click elsewhere, puts Tab on the selected item instead of the first row, and no longer stays "Loading" for good when a lazy branch's children arrive initems. In multiple mode the same selection in another order is no longer pending, and choosing the selected item again sends nothing.sb-voxel: a newyaworpitchfrom the page replaces the user's turn, so sliders and a write-back ofsb-orbitstay in step. Only the first finger and the main mouse button drag (a pinch or a right click spun the model),sb-orbitfires once per turn, the pitch stops at ±89° without a dead zone, and the planet draws about 30% faster. In its docs and its Playground, the angle sliders follow a drag (a newsync:option in a component'splayground:front matter).- Component pages: switching a boolean control off in the Playground switches the preview off too (e.g.
sb-toggle'schecked), so it matches the markup shown. - The site's autoloader no longer waits forever for a module that loads but never defines its tag: after 10 s it reports it, so
readyand the cloak don't hang on it. Mission Control's altitude chart has an accessible name, and its starfield is decoration for screen readers.
Known issues
- Datastar's morph is not re-entrant with Rocket components that are reordered by id (starfederation/datastar#1209, still open). Starbase avoids the pattern.
- The form-like components are not form-associated yet (Rocket can't declare it): validity and
required,<fieldset disabled>,<label for>and theformattribute don't reach them. - Rocket's
observePropsignores an attribute write whose decoded value is unchanged; the value components watch their value attribute themselves. A reproduction is indocs/repro/rocket-observeprops-equal-value/.