{"_id":"@asnewyla/unstyled-radio","name":"@asnewyla/unstyled-radio","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@asnewyla/unstyled-radio","version":"0.2.0","description":"Unstyled radio input primitive with accessibility","license":"MIT","repository":{"type":"git","url":"git+https://github.com/xavierDelaFuente/xd-components.git","directory":"packages/unstyled-radio"},"publishConfig":{"access":"public"},"main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"sideEffects":false,"keywords":["react","radio","unstyled","accessible"],"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"devDependencies":{"react":"^18.3.0","react-dom":"^18.3.0","tsup":"^8.1.0","vitest":"^2.0.0","@vitest/coverage-v8":"^2.0.0","@testing-library/react":"^16.0.0","@testing-library/user-event":"^14.5.0","@testing-library/jest-dom":"^6.4.0","jsdom":"^24.0.0","typescript":"^5.5.0"},"scripts":{"build":"tsup","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","type-check":"tsc --noEmit"},"_nodeVersion":"24.19.0","_id":"@asnewyla/unstyled-radio@0.2.0","dist":{"integrity":"sha512-VUBmhqSNIlNo9k9ipqkSHSkIU3rR72oJy+Sqp8RS8b41batpt5ev55zqLlPHUfKjWI5ICBafB7r4ybq8wjG9QQ==","shasum":"7c16fb6ff8a096c0adf8981ba6e7c7e01ed21e1e","tarball":"https://registry.npmjs.org/@asnewyla/unstyled-radio/-/unstyled-radio-0.2.0.tgz","fileCount":9,"unpackedSize":16911,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDV3KL2RgtRhDCMiybf7fFwYFaZyaa4DOJaFgoi6pxoqgIhAPiAYjtE2+x3my+EVbeojf7z/9gTx2cNjk5P1XEWElsN"}]},"_npmUser":{"name":"asnewyla","email":"asnewyla@gmail.com"},"directories":{},"maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/unstyled-radio_0.2.0_1787564634351_0.5044933144803845"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-24T09:43:54.207Z","0.2.0":"2026-08-24T09:43:54.507Z","modified":"2026-08-24T09:43:54.728Z"},"maintainers":[{"name":"asnewyla","email":"asnewyla@gmail.com"}],"description":"Unstyled radio input primitive with accessibility","keywords":["react","radio","unstyled","accessible"],"repository":{"type":"git","url":"git+https://github.com/xavierDelaFuente/xd-components.git","directory":"packages/unstyled-radio"},"license":"MIT","readme":"# @asnewyla/unstyled-radio\n\nUnstyled, accessible radio input primitive. Handles checked, focus, and\ninvalid-state tracking without imposing any visual styling — the base\nlayer under `@asnewyla/radio`.\n\n## Install\n\n```bash\nnpm install @asnewyla/unstyled-radio\n```\n\n## Usage\n\n```tsx\nimport { UnstyledRadio } from '@asnewyla/unstyled-radio';\n\n// Uncontrolled — a single radio, or a group sharing a native `name`\n<UnstyledRadio aria-label=\"Option A\" name=\"choice\" defaultChecked />\n<UnstyledRadio aria-label=\"Option B\" name=\"choice\" />\n\n// Controlled\n<UnstyledRadio\n  aria-label=\"Option A\"\n  checked={selected === 'a'}\n  onChange={() => setSelected('a')}\n/>\n\n// Invalid state\n<UnstyledRadio aria-label=\"Option A\" invalid />\n```\n\n### Props\n\n| Prop | Type | Default |\n|---|---|---|\n| `checked` / `defaultChecked` | `boolean` | — |\n| `onChange` | `(event: React.ChangeEvent<HTMLInputElement>) => void` | — |\n| `disabled` | `boolean` | `false` |\n| `invalid` | `boolean` | `false` |\n\nUncontrolled by default, same as a native `<input type=\"radio\">` — pass\n`checked` + `onChange` to control it yourself.\n\nState is exposed via `data-checked`, `data-focused`, `data-disabled`, and\n`data-invalid`/`aria-invalid` — style off these attributes rather than\n`:checked`, for the same DevTools-visible, test-stable reasons every other\n`@asnewyla/*` primitive uses `data-*` for state.\n\n### A real multi-radio group needs `RadioGroup`, not several bare `UnstyledRadio`s\n\nTwo `UnstyledRadio`s sharing a native `name` get correct browser-level\nexclusivity for free — clicking one genuinely unchecks the other at the\nDOM level, no JavaScript required. But each `UnstyledRadio` only learns\nabout its **own** checked state through its **own** `onChange`; browsers\nnever fire a `change` event on a radio that gets deselected as a side\neffect of a sibling being selected. That means `data-checked` on the\ndeselected radio goes stale — the underlying `<input>` really is\nunchecked, but the attribute you'd style off doesn't know it yet.\n\nFor a real, visually-correct multi-radio group, use `RadioGroup` (a\nshared source of truth for which value is selected) rather than several\nindependent, uncontrolled `UnstyledRadio`s. `UnstyledRadio` on its own is\nreliable for a single isolated radio, or for any usage where you fully\ncontrol `checked` yourself.\n\n## License\n\nMIT\n","readmeFilename":"","_rev":"1-5596f2bb229046456365070744301822"}