Independent reviews. IonBin has no partnerships with the tools on this page and was not paid for these listings. Our evaluations are our own, based on public documentation and our research. Product names are trademarks of their owners and are used for identification only. How disclosure works.

Components / Unstyled React primitives

Radix Primitives

Use focused UI building blocks when you need control over markup and appearance.

Documentation reviewed

Source review

What this status means

Understand the resource

What it is.

Radix Primitives is a React library for common interaction patterns such as dialogs, menus, tabs and tooltips. Its component parts handle state and many keyboard details while leaving styling to the application. This review covers Primitives rather than the separate Radix Themes offering.

When it is useful

It fits teams building a shared React component layer or improving a custom interface one control at a time. It also helps explain the behavior beneath many styled wrappers already in the catalog.

A proposed application

Put it to work.

This example illustrates a possible use. The proposed workflow and expected result are separate from the bounded checks recorded below.

Try this

Proposed workflow: replace three different edit-record modals with one Radix Dialog wrapper. Include a title and description, make the first field labelled, and restore focus to the row's Edit button on cancellation. Add a second review step for unsaved changes instead of assuming Escape should discard work. Our fixture tested dialog mechanics, not database updates or that unsaved-change policy.

Result to aim for

A consistent editing shell that can be styled for the product while keeping data validation and persistence explicit.

Before you start

What you need.

  • A compatible React application. The pinned @radix-ui/react-dialog 1.3.1 manifest accepts React 16.8 through 19; the fixture used React 19.3.1.
  • Styles, useful accessible names and careful forwarding of props and refs when composing custom children. Primitives is MIT licensed.

The practical boundaries

What to watch for.

  • The asChild composition option can lose behavior when a custom child drops props or refs, or uses an unsuitable element.
  • Keep separately installed Radix packages aligned; shared dependency duplication can complicate upgrades and bundle size.
  • A modal can constrain interaction while open; it cannot establish who may read or change a record.

Review record

What we could establish.

  • Why included (2026-10-19): Adds the widely used primitive layer behind many React kits, so readers can compare that foundation with finished styling systems. GitHub reported 19,406 stars for the upstream repository (radix-ui/primitives); the sampled default-branch commit is dated 2026-10-14. This is a dated popularity/activity snapshot, not a measured growth rate or safety ranking.
  • Public official documentation and declared package requirements reviewed. The example above is a proposed workflow; executed checks are listed separately below.
  • Earlier selector, focus-timing and setup probes remain in the retained evidence. Final conclusions use the corrected bounded tests and keep unmet coverage explicit.
Source coverage and runtime coverage are separate

The source-review notes describe documentation and identity. The account-free evaluation below records exactly which public interaction or local fixture was checked, what happened, and what remains untested.

Check current access, terms, licensing and data handling before using a resource with your own material.

Runtime and security evaluation

What the evaluation covers.

Bounded runtime checkedAccount-free ·

The official edit-profile dialog passed opening, six Tab steps and Escape focus restoration. The pinned Dialog 1.3.1 fixture passed six additional checks, including state callbacks and React text insertion. Save changes was never activated.

Methods: Public HTTP response · Public browser sample · Local package fixture. A completed check covers the stated sample; it is not a safety certification.

Target
https://www.radix-ui.com/primitives/docs/components/dialog plus a local @radix-ui/react-dialog fixture
Version or capture
Local @radix-ui/react-dialog 1.3.1; React and React DOM 19.3.1 for the Dialog fixtures. Public demo is separately unversioned.
Integrity scope
Package archive SHA-256 485336a3a4118d0f7e49504a3b2752c8975ea0e5e3ad1c944ff055d2d2fc15f2 (npm SHA-512 integrity matched). Public document SHA-256 6b061c025b95533dfa1b6ec88666c7471e4a3a6d2e3f38be70e70a004be7572e; response-body scope only.

Test conditions

  • Chrome 155.0.8059.82, 1280 x 900 desktop viewport; UTC browser context.
  • Fresh temporary browser profile and context; no inherited account storage. Child environment allowed only runtime paths, with credential variables omitted.
  • Public HTTPS GET/HEAD only; form submission, non-read methods, WebSockets, service workers and downloads blocked. Selected telemetry requests were blocked.
  • Exact direct dependencies; 38-package lock installed with --ignore-scripts, empty user/global npm configs, isolated cache and allowlisted environment. No lifecycle install scripts ran.
  • Local browser responses served only the authored fixture, pinned bundle or stylesheet. External HTTP(S) requests were denied, with zero recorded attempts in the final fixture. WebSocket attempts were blocked but not counted.
  • Existing Rolldown 1.2.14 bundled inspected prebuilt exports without running upstream build scripts.

Individual checks and observations

  1. Public sample response

    pass

    Public HTTP response: Anonymous public GET; capture status, response-body hash and selected headers.

    Observed: HTTP 200; https://www.radix-ui.com/primitives/docs/components/dialog. Reachability only.

  2. Keyboard open and dialog semantics

    pass

    Public browser sample: Focus the first documented dialog trigger; press Enter; inspect visible dialog and accessible-name reference.

    Observed: A visible dialog opened; aria-labelledby target present=True. Presence of a reference is not a screen-reader test.

  3. Bounded dialog focus containment

    pass

    Public browser sample: Press Tab six times while the sample remains open and inspect focus containment after each press.

    Observed: All six settled Tab samples stayed inside the dialog. This does not establish every focus path or nested-overlay behavior.

  4. Escape and focus restoration

    pass

    Public browser sample: Press Escape, wait for exit animation and inspect closed state plus focus on original trigger.

    Observed: Closed=true; trigger focus restored=true. No save action or form submission.

  5. Pinned dialog opening and labels

    pass

    Local package fixture: Press Enter on the authored trigger and inspect the dialog name and description relationships.

    Observed: {"title":"Synthetic settings","description":"A synthetic local form; nothing is saved."}

  6. Initial focus

    pass

    Local package fixture: Inspect focused element after the modal opens.

    Observed: {"inside":true,"tag":"INPUT"}

  7. Tab containment

    pass

    Local package fixture: Press Tab six times with a brief focus-settlement wait; inspect containment.

    Observed: [true,true,true,true,true,true]

  8. React text insertion boundary

    pass

    Local package fixture: Render a synthetic HTML-looking string as a React child and inspect text, image count and recorded HTTP(S) request attempts.

    Observed: Literal text retained=true; image nodes=0; recorded HTTP(S) request attempts=0. React text composition only; no HTML sanitizer tested. WebSocket attempts were blocked but not counted.

  9. Escape closure and restoration

    pass

    Local package fixture: Press Escape and inspect removed dialog plus focus on original trigger.

    Observed: {"closed":true,"focused":true}

  10. Close action and state callback

    pass

    Local package fixture: Reopen by pointer, activate the component Close control and inspect open-change callbacks.

    Observed: Open state callbacks [true,false,true,false]; no persistence handler attached.

Security findings and boundaries

Passive inspection of official public response headers and request hosts, declared package metadata, and the exact local fixture where stated. No exploitation, authentication, private input or backend writes.

Observed · info

Dialog state stayed local in the fixture

The synthetic open/close callback sequence was true, false, true, false and zero HTTP(S) request attempts were recorded. WebSocket attempts were blocked but not counted. That describes the authored fixture; production handlers can add network and persistence behavior.

Observed · info

Sampled response and request surface

The anonymous HTTPS demo response included strict-transport-security. Requests attempted 2 additional host(s), including static.cloudflareinsights.com, www.googletagmanager.com. The guard blocked 2 request(s). Host attempts include blocked requests; this does not establish retained data or exploit resistance.

Observed · info

Pinned fixture network boundary

All six @radix-ui/react-dialog fixture checks completed with zero recorded HTTP(S) request attempts and zero page errors. WebSocket attempts were blocked but not counted. This applies to the small authored fixture; it is not a claim about every export, dependency or integration.

Practical caveats

  • The asChild composition option can lose behavior when a custom child drops props or refs, or uses an unsuitable element.
  • Keep separately installed Radix packages aligned; shared dependency duplication can complicate upgrades and bundle size.
  • A modal can constrain interaction while open; it cannot establish who may read or change a record.

What remains untested

  • Only Dialog was installed. No whole-library, nested overlay, router, hydration or mobile assistive-technology test was performed.
  • The HTML-looking string stayed literal through React child rendering; dangerouslySetInnerHTML and HTML sanitizers were not tested.

Security limits

  • No authentication, authorization, tenant isolation, retention or backend processing was tested.
  • No comprehensive source/dependency audit, vulnerability scan or security certification. Header presence or absence describes one response, not the safety of a product.
  • Request guards can alter normal page behavior. Full browser, mobile, assistive-technology and performance coverage is outside this evaluation.

Evaluation sources

  1. Official documentation
  2. Official evaluated sample
  3. Upstream repository
  4. GitHub repository snapshot endpoint

    Star count and repository identity observed 2026-10-19.

  5. Sampled source revision

    Default branch snapshot; not a claim that the hosted demo deploys this exact commit.

  6. Package manifest snapshot

    Exact registry version and dependency/license declaration; installed only where the evaluation says so.

  7. Radix accessibility guidance
  8. Composition and custom-child requirements

Download this evaluation record (JSON)

Follow the evidence

Sources and further reading.

  1. Official documentation
  2. Official evaluated sample
  3. Upstream repository
  4. GitHub repository snapshot endpoint

    Star count and repository identity observed 2026-10-19.

  5. Sampled source revision

    Default branch snapshot; not a claim that the hosted demo deploys this exact commit.

  6. Package manifest snapshot

    Exact registry version and dependency/license declaration; installed only where the evaluation says so.

  7. Radix accessibility guidance
  8. Composition and custom-child requirements

Keep exploring

More in components.

View category

Documentation reviewed

shadcn/ui

Build an owned component layer with documented starting patterns.

Documentation reviewed

coss ui

Start from Base UI-backed product components.

Documentation reviewed

ReUI

Use documented patterns for dense product interfaces.