Skip to content
jbrxlPublic

About

Headless UI Native - Completely unstyled, accessible UI components for React Native, ported from Headless UI.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

bareboard logo

@bareboard/react-native

A set of completely unstyled, fully accessible UI components for React Native.

Early stage: @bareboard/react-native is experimental and its API may change without notice. It is published on npm. See Status.


Why @bareboard/react-native

Building accessible interactions is hard: menus, listboxes, dialogs, comboboxes and disclosures each need state, focus handling and the right accessibility roles. Headless UI solves this for the web by providing those behaviours without any styles, so you keep full control over the look.

@bareboard/react-native brings that approach to React Native. It provides the same kind of components, with the same composition model, and leaves every visual decision to your app:

  • Unstyled: components render your children and accept style props. Nothing is imposed on the look.
  • Stateful by render prop: components expose their state, such as open, to the children so the UI can react to it.
  • Accessible by default: accessibility state and roles are set for you, and the caller can still provide its own accessibilityState.

Relationship with Headless UI

@bareboard/react-native is a React Native port of Headless UI, created by Tailwind Labs. It is not affiliated with or endorsed by Tailwind Labs.

This repository was created from tailwindlabs/headlessui, but its history starts at the React Native scaffold: the earlier history, including the React and Vue packages, is not on main.

Status

@bareboard/react-native is experimental. Version 0.2.1 is published on npm as a public package. The behaviour is covered by unit tests, and a Playwright test checks the combobox on the web. Testing on real devices is still to come.

Limits of the React Native port

@bareboard/react-native keeps the components, the state machines and the accessibility roles of Headless UI. Some parts of the web API have no equivalent in React Native and are not implemented:

  • Positioning: anchor positions a portalled panel against its trigger (see below), but anchored panels do not flip when they reach the edge of the screen. The other overlays of the playground are placed with absolute positioning.
  • Transitions: Transition and the transition prop animate opacity and scale, with durations in milliseconds (enter and leave). CSS class swaps and the appear prop are not supported. unmount is supported. The transition prop is on the panels of Disclosure, Popover, Menu, Listbox and Combobox, and on Dialog, which animates its whole content.
  • Polymorphism: there is no as prop. Components render React Native primitives, and the app chooses the children.
  • Portal and modal: the portal prop of Menu, Popover, Listbox and Combobox renders the panel above the rest of the app, and keeps its React context. Inside a PortalGroup, the panel is drawn by the group, which lets touches through to the page below. Without a group, it is drawn in a Modal, which covers the page, so touches and screen readers stay in the panel. The modal prop draws a full-screen backdrop that closes the panel on press, and only applies with portal. The anchor prop places a portalled panel against its trigger: bottom, bottom start, bottom end, top, top start or top end. The panel takes the width of the trigger as its minimum width. Mount PortalGroup once, around the whole app. Its target ref receives the view the portals are drawn in, to measure it. With transition in a Modal, the leave animation is cut short, because the Modal hides at once. The Portal and PortalGroup components are exported separately.
  • Auto focus: autoFocus works on Input, Textarea and ComboboxInput, where it is the native TextInput prop. Other components do not take focus on mount: React Native has no keyboard focus outside of web builds, so their autoFocus prop is not implemented.
  • Form fields: there are no name and form props on Checkbox, Switch, RadioGroup, Listbox and Combobox, because there is no form submission to feed.
  • Forms: there is no <form> element and no FormData helper.
  • Devices: the behaviour has not been tested on iOS or Android devices yet.

Packages

Name Location Description
@bareboard/react-native packages/react-native Headless UI components for React Native
playground-expo-uniwind playgrounds/expo-uniwind Expo app styled with Uniwind, with examples for each component

The components include Button, Checkbox, Combobox, Dialog, Disclosure, Listbox, Menu, Popover, RadioGroup, Select, Switch, Tabs, Textarea and Transition, among others.

Installation

Install the package from npm, with the React and React Native versions your app already uses:

pnpm add @bareboard/react-native
npm install @bareboard/react-native

react (18 or 19) and react-native are peer dependencies: your app provides them. See the package README for more details.

Example

This is a simplified version of the disclosure example from the playground, without its styles. Components are imported from the package, and the styles are yours.

import { Disclosure, DisclosureButton, DisclosurePanel } from '@bareboard/react-native'
import { Text } from 'react-native'

export function ShippingDetails() {
  return (
    <Disclosure>
      {({ open }) => (
        <>
          <DisclosureButton>
            <Text>{open ? 'Hide' : 'Show'} the shipping details</Text>
          </DisclosureButton>

          <DisclosurePanel>
            <Text>Orders ship within two business days.</Text>
          </DisclosurePanel>
        </>
      )}
    </Disclosure>
  )
}

Inside this repository, the playground imports the package as a workspace dependency.

Getting started

To work on the repository, you need Node.js 24.15 or newer, and pnpm. With Corepack, corepack enable provides the pnpm version pinned in package.json.

git clone https://github.com/jbrxl/bareboard.git
cd bareboard
pnpm install

Then run the checks, or open the playground:

pnpm check
pnpm test
pnpm dev

The root package.json holds the commands used across the workspaces. pnpm lint and pnpm typecheck run the scripts of every package in turn.

Development

See CONTRIBUTING.md for the coding standards, the test commands and the playground. AGENTS.md describes the layout and conventions of the repository.

Contributing

If you're interested in contributing, please read our contributing docs before submitting a pull request.

License

MIT. Headless UI was originally created by Tailwind Labs and is licensed under the MIT License. See LICENSE.

About

Headless UI Native - Completely unstyled, accessible UI components for React Native, ported from Headless UI.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages