Skip to content

MUI Core /Base UI

A blank canvas for
total flexibility

Base UI gives you a set of foundational "headless" components that you can build with using any styling solution you choose—no need to override any default style engine or theme.

Why Base UI

Essential building blocks
for sleek and accessible UIs

Base UI abstracts away the more frustrating aspects of UI development—like accessibility, cross-browser compatibility, and event handling—so you can skip ahead to design implementation.

Alternative to libraries such as:

Unstyled components

Choose your own
CSS adventure

Base UI's skeletal components give you a sturdy foundation to apply custom styles with ease. With no defaults to override, you're free to start from scratch using vanilla CSS, Tailwind CSS, MUI System, or any other framework you prefer.






Much more
First page
import { Tabs } from '@mui/base/Tabs';
import { TabsList } from '@mui/base/TabsList';
import { TabPanel } from '@mui/base/TabPanel';
import { Tab } from '@mui/base/Tab';
import { styled } from '@mui/system';

const StyledTabsList = styled('div')`
  min-width: 300px;
  background-color: var(--primary);
  border-radius: 12px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  align-content: space-between;
  box-shadow: var(--shadow);

const StyledTabPanel = styled('div')`
  width: 100%;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 0.875rem;

const StyledTab = styled('button')`
  font-family: 'IBM Plex Sans', sans-serif;
  color: white;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: bold;
  background-color: transparent;
  width: 100%;
  padding: 12px;
  margin: 6px 6px;
  border: none;
  border-radius: 7px;
  display: flex;
  justify-content: center;
  transition: all 120ms ease;
  user-select: none;

  &:hover {
    background-color: var(--primary-hover);

  &:focus-visible {
    color: #FFF;
    outline: 2px solid rgba(255,255,255,0.8);
    outline-offset: 2px;

  &.base--selected {
    background-color: #FFF;
    color: var(--primary);

<Tabs selectionFollowsFocus defaultValue={0}>
  <TabsList slots={{ root: StyledTabsList }}>
    <Tab slots={{ root: StyledTab }}>One</Tab>
    <Tab slots={{ root: StyledTab }}>Two</Tab>
    <Tab slots={{ root: StyledTab }}>Three</Tab>
  <TabPanel slots={{ root: StyledTabPanel }} value={0}>
    First page
  <TabPanel slots={{ root: StyledTabPanel }} value={1}>
    Second page
  <TabPanel slots={{ root: StyledTabPanel }} value={2}>
    Third page


Endless possibilities
with a lightweight API

With Base UI, you have the freedom to decide how much you want to customize a component's structure and style.

Applying custom CSS rules

Your CSS, your rules. With Base UI there are no styles to override, so you can start with a clean slate.

Overriding subcomponent slots

Default DOM structure doesn't suit your needs? Replace any node with the element you prefer using the `slots` prop.

Creating custom components using hooks

Base UI includes low-level hooks for adding functionality to your own fully custom-built components.
import clsx from 'clsx';
import { styled } from '@mui/system';
import { SwitchUnstyled } from '@mui/base/Switch';
import { useSwitch } from '@mui/base/useSwitch';

const StyledSwitchRoot = styled('span')(`
  font-size: 0;
  position: relative;
  display: inline-block;
  width: 40px;
  height: 24px;
  margin: 10px;
  cursor: pointer;
  border-radius: 16px;
  background: #A0AAB4;

  &.Mui-disabled {
    opacity: 0.4;
    cursor: not-allowed;

  &.Mui-checked {
    background: #007FFF;
    & .MuiSwitch-thumb {
      left: 20px;

  &.Mui-focusVisible {
    outline: 2px solid #007FFF;
    outline-offset: 2px;

const StyledSwitchInput = styled('input')`
  cursor: inherit;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  opacity: 0;
  z-index: 1;
  margin: 0;

const StyledSwitchThumb = styled('span')`
  display: block;
  width: 16px;
  height: 16px;
  top: 4px;
  left: 4px;
  border-radius: 16px;
  background-color: #FFF;
  position: relative;
  transition-property: all;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 120ms;

  &.Mui-checked {
    left: 20px;

function SwitchFromHook(props) {
  const {
  } = useSwitch(props);

  const stateClasses = {
    'Mui-checked': checked,
    'Mui-disabled': disabled,
    'Mui-focusVisible': focusVisible,

  return (
    <StyledSwitchRoot className={clsx(stateClasses)}>
      <StyledSwitchThumb className={clsx(stateClasses)} />
      <StyledSwitchInput {...getInputProps()} aria-label="Demo switch" />

function App() {
  return (
        root: StyledSwitchRoot,
        input: StyledSwitchInput,
        thumb: StyledSwitchThumb,
        input: { 'aria-label': 'Demo switch' },
    <SwitchFromHook />

Nhost's dashboard

Screenshot displaying part of the Nhost dashboard that used Base UI to be built.

Nhost's new dashboard, powered by Base UI   /  View the blog post

“After considering various options, we decided to migrate our custom components to Material UI, and that's when we discovered Base UI. As a set of headless components, it offered exactly what we needed to implement our design system while maintaining full customizability. The focus on accessibility was also a big plus, as it ensured that our dashboard was usable by everyone. Low-level component hooks were just the icing on the cake.”

Szilárd Dóró's profile picture

Szilárd Dóró

Senior Software Engineer


Join our global community

Base UI wouldn't be possible without our global community of contributors. Join us today to get help when you need it, and lend a hand when you can.

  • Base UI vs. Material UI

    Base UI features many of the same components as Material UI, but without the Material Design implementation.

  • Does it come with styles?

    Base UI is not packaged with any default theme or built-in style engine. This makes it a great choice if you need complete control over how your app's CSS is implemented.