segmented-pill
v0.1.3
Published
Accessible segmented control for React and Vue with an optional sliding pill.
Downloads
326
Maintainers
Readme
Segmented Pill
Accessible segmented control for React and Vue. Static by default, with optional sliding motion.
npm
npm install segmented-pillpnpm
pnpm add segmented-pillBun
bun add segmented-pillGeist is optional. If your app already loads it, Segmented Pill uses it automatically; otherwise it falls back to your system sans-serif font.
React
import { useState } from "react";
import { SegmentedPill } from "segmented-pill/react";
import "segmented-pill/style.css";
const items = [
{ value: "overview", label: "Overview" },
{ value: "activity", label: "Activity" },
{ value: "settings", label: "Settings" },
];
export function Navigation() {
const [value, setValue] = useState("overview");
return <>
<SegmentedPill
aria-label="Section"
items={items}
value={value}
onValueChange={setValue}
animated
/>
{value === "overview" && <Overview />}
{value === "activity" && <Activity />}
{value === "settings" && <Settings />}
</>;
}Vue
<script setup>
import { ref } from "vue";
import { SegmentedPill } from "segmented-pill/vue";
import "segmented-pill/style.css";
const value = ref("overview");
const items = [
{ value: "overview", label: "Overview" },
{ value: "activity", label: "Activity" },
{ value: "settings", label: "Settings" },
];
</script>
<template>
<SegmentedPill
v-model="value"
aria-label="Section"
:items="items"
animated
/>
<Overview v-if="value === 'overview'" />
<Activity v-else-if="value === 'activity'" />
<Settings v-else />
</template>API
| Purpose | React | Vue |
| --- | --- | --- |
| Options | items | items |
| Controlled value | value | v-model |
| Initial value | defaultValue | defaultValue |
| Change event | onValueChange | change |
| Sliding pill | animated | animated |
animated defaults to false. When enabled, the pill slides with a small stretch-and-squash response. Reduced-motion preferences always disable both effects.
Arrow keys, Home, End, Enter, and Space work automatically. Disabled items are skipped, focus stays visible, and ARIA selection state remains synchronized. Add aria-label or aria-labelledby to every control.
Theme
.my-control {
--segmented-font-family: "Geist", "Geist Variable", sans-serif;
--segmented-track: #e9e3db;
--segmented-pill: #fffdf9;
--segmented-focus: #8a5a32;
--segmented-radius: 12px;
}MIT
