# coss vs shadcn/Radix assumptions
Use this guide when adapting snippets that were originally written with shadcn/Radix mental models.
## Core idea
coss is close to shadcn ergonomically, but its primitives and composition model are aligned to Base UI patterns.
## High-impact differences
- Do not assume every shadcn pattern translates 1:1.
- Verify trigger and popup composition from coss docs before coding.
- Apply `asChild` -> `render` only on coss parts that explicitly support `render`.
- Prefer coss component names and exports as documented (`DialogPopup`, `MenuPopup`, `SelectPopup`, etc.).
- Some legacy aliases may exist, but primary coss names should be preferred in new examples.
- Prefer styled coss exports by default (for example `Slider`, `SliderValue`) and use `*Primitive` only for advanced/custom composition.
- When only Base UI helpers are needed (`useRender`, `mergeProps`, `CSPProvider`, `DirectionProvider`), prefer `@coss/ui/base-ui/*` re-exports over direct `@base-ui/react` dependency.
- For Select migration, replace children-only option derivation with an `items`-first pattern where possible, then map options consistently in `SelectPopup`.
- For OTP fields, migrate off the `input-otp` package to coss `@coss/otp-field`: rename components (`OTPField`, `OTPFieldInput`, `OTPFieldSeparator`), use `length` and `onValueChange`, and drop `InputOTPGroup` / slot `index` (see example below).
## Practical migration examples
Use these snippets as fast conversion templates when migrating shadcn/Radix code.
### Composition: `asChild` -> `render`
```tsx
// shadcn/Radix
```
```tsx
// coss/Base UI
}>Open
```
### Menu actions: `onSelect` -> `onClick`
```tsx
// shadcn/Radix
Open
```
```tsx
// coss/Base UI
```
### Select: `items`-first + placeholder on `SelectValue`
```tsx
// shadcn/Radix
```
```tsx
// coss/Base UI
const items = [
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
];
```
### Toggle Group: `type` -> `multiple`
```tsx
// shadcn/Radix
DailyWeekly
```
```tsx
// coss/Base UI
DailyWeekly
```
### Slider: scalar single-value usage in coss
```tsx
// shadcn/Radix
```
```tsx
// coss/Base UI
```
### Accordion: `type/collapsible` -> coss defaults
```tsx
// shadcn/Radix
...
```
```tsx
// coss/Base UI
...
```
### OTP Field: `input-otp` package → `@coss/otp-field`
coss wraps [Base UI OTP Field](https://base-ui.com/react/components/otp-field) (`OTPFieldPreview`). Remove the `input-otp` dependency and align with the new names and root props.
```tsx
// shadcn / input-otp
```
```tsx
// coss
```
- `InputOTPGroup` is not used; optional `size="lg"` lives on `OTPField`.
- Render one `OTPFieldInput` per character in order; do not pass `index`.
## Migration checklist
1. Confirm the exact coss imports from docs.
2. Confirm child structure requirements (trigger/header/panel/footer/items/groups).
3. Confirm prop names and semantics from the coss docs page.
4. Validate with at least one coss particle example.
## Per-component migration notes
For the full component registry, see `../component-registry.md`.
## Anti-patterns
- Copy/paste shadcn examples and only change import path.
- Using undocumented props because they exist in other ecosystems.
- Omitting required subcomponents in overlays/forms because the source snippet did.