[ @sdxc/ui ]
SelectionIndicator
A small marker that stays invisible, while still reserving its own layout slot.
View code
<div mix={[vstack({ gap: 1, align: "stretch" }), on<HTMLDivElement, "change">("change", readOrder)]}>
<Header id="preview-sort-heading">Sort packages by</Header>
<div role="group" aria-labelledby="preview-sort-heading" mix={[vstack({ gap: 0, align: "stretch" })]}>
{orders.map((order) => (
<label
key={order.value}
mix={[
hstack({ gap: 2, align: "center" }),
p(2),
css({ cursor: "pointer", borderRadius: "var(--ui-radius-md)" }),
]}
>
<SelectionIndicator aria-selected={order.value === selected ? "true" : "false"}>
<CheckIcon />
</SelectionIndicator>
<input
type="radio"
name="preview-order"
value={order.value}
checked={order.value === selected}
mix={[ariaChecked(), visuallyHidden()]}
/>
{order.label}
</label>
))}
</div>
<Text>Nothing shifts sideways as the marker moves.</Text>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/ui remiximport "@sdxc/ui/theme.css";Usage
import { SelectionIndicator } from "@sdxc/ui";Renders a marker that stays present in the layout at all times but only
becomes visible once its host carries aria-selected="true" or a truthy
aria-current, so sibling content never reflows on selection change.
Examples
Tab underline
View code
let activeTab = "billing";
<Tabs>
<Tabs.List aria-label="Settings sections">
{sections.map((section) => (
<Tabs.Tab
key={section.id}
href={"#" + section.id}
aria-selected={activeTab === section.id ? "true" : "false"}
mix={[
relative(),
on<HTMLAnchorElement, "click">("click", (event) => {
event.preventDefault();
activeTab = section.id;
void handle.update();
}),
]}
>
{section.label}
<SelectionIndicator
aria-selected={activeTab === section.id ? "true" : "false"}
mix={[absolute(), insIs(0), insIe(0), insBe("-0.125rem"), is("auto"), bs("0.125rem"), bg("brand.solid")]}
/>
</Tabs.Tab>
))}
</Tabs.List>
</Tabs>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
Also accepts everything in TagProps<"div">.