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

Base UI

Build a distinct interface without rebuilding dialog, menu and focus behavior from scratch.

Documentation reviewed

Source review

What this status means

Understand the resource

What it is.

Base UI provides composable React controls without a finished visual theme. You assemble parts such as a dialog trigger, popup, title and close button, then supply your own styles. It is a foundation for a product design system, not a page template or a backend.

When it is useful

Choose it when a React product needs a strong brand treatment and your team can maintain shared component wrappers. It is especially useful for replacing several slightly different implementations of the same overlay or input.

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: turn a knowledge-base article's settings into a reusable dialog. Give it a clear title, a labelled summary field and separate Cancel and Save actions. Reuse that wrapper in the collection editor, then test keyboard entry, errors, dismissal and focus return with real content. The evaluation below used a smaller synthetic dialog and did not save an article.

Result to aim for

One styled settings pattern with explicit focus and state behavior, plus a checklist for the application-specific save and error flows.

Before you start

What you need.

  • A React application and a package manager; the inspected @base-ui/react 1.9.0 manifest supports React 17, 18 or 19.
  • Your own styling, accessible labels, visible focus treatment and application tests. The package is MIT licensed; preserve applicable notices.

The practical boundaries

What to watch for.

  • Unstyled does not mean finished: contrast, target size and visible focus still depend on your CSS.
  • Portals create a separate rendering location. Check stacking, scroll locking and nested overlays in your app.
  • Opening a protected action in a dialog does not authorize it. Enforce permissions and validation in the application backend.

Review record

What we could establish.

  • Why included (2026-10-19): Adds an actively maintained unstyled foundation with a different composition API from the catalog's styled component kits. GitHub reported 11,181 stars for the upstream repository (mui/base-ui); the sampled default-branch commit is dated 2026-10-19. 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 notification dialog passed keyboard opening, settled focus containment and Escape restoration. A separate @base-ui/react 1.9.0 fixture passed six checks for labels, focus, state callbacks and literal React text insertion. Neither test saved data.

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://base-ui.com/react/components/dialog plus a local @base-ui/react fixture
Version or capture
Local @base-ui/react 1.9.0; React and React DOM 19.3.1 for the Dialog fixtures. Public demo is separately unversioned.
Integrity scope
Package archive SHA-256 bcb2f90923d9be3200cde3b27cb1a8d1c832a4f5bc7d3709a4f4c99d3de771ab (npm SHA-512 integrity matched). Public document SHA-256 017006d6215b97fc5e5571b99b34a67aee57971a5eb21a7a372c7e8ed15c0338; 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://base-ui.com/react/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, allowing browser chrome or focus guards.

    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]; dialog removed=true; 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.

Documented · caution

Focus behavior still needs visible styling

Base UI documents automatic focus management but leaves visible focus styling to the application. The fixture's blue outline was authored for the test, not supplied by the library.

Observed · info

Sampled response and request surface

The anonymous HTTPS demo response included content-security-policy, strict-transport-security, x-content-type-options, x-frame-options, referrer-policy. Requests attempted 1 additional host(s), including www.googletagmanager.com. The guard blocked 1 request(s). Host attempts include blocked requests; this does not establish retained data or exploit resistance.

Observed · info

Pinned fixture network boundary

All six @base-ui/react 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

  • Unstyled does not mean finished: contrast, target size and visible focus still depend on your CSS.
  • Portals create a separate rendering location. Check stacking, scroll locking and nested overlays in your app.
  • Opening a protected action in a dialog does not authorize it. Enforce permissions and validation in the application backend.

What remains untested

  • The full @base-ui/react package was installed, but only Dialog was exercised. Other controls, nested overlays, server rendering, mobile gestures and assistive technologies were not tested.
  • The synthetic fixture used authored focus styles; it does not establish the accessibility of a team's finished visual theme.

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. Accessibility responsibilities

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. Accessibility responsibilities

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.