# @eduzz/ui-layout

> Components de UI padrão das aplicações, aqui você vai encontrar:

Latest version **5.0.0** (published 2026-08-31) · MIT license · 0 weekly downloads

## Install

```sh
npm install @eduzz/ui-layout
pnpm add @eduzz/ui-layout
yarn add @eduzz/ui-layout
bun add @eduzz/ui-layout
```

## Health

**Score 60/100 (C)** — status: active.

Positive: has types; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no esm support.

## Facts

| | |
|---|---|
| Version | 5.0.0 |
| Published | 2026-08-31 |
| First published | 2023-06-29 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 7 |
| Unpacked size | 1.8 MB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Eduzz Team |
| Maintainers | danieloprado, caferrari, luanlmd, vitorvmrs, jonathasprodrigues, lcscefali, jcrjunior |
| Keywords | eduzz, react, layout |

## Links

- npm: https://www.npmjs.com/package/@eduzz/ui-layout
- npm.io page: https://npm.io/package/@eduzz/ui-layout

## Dependencies (7)

- [clsx](https://npm.io/package/clsx.md) ^2.1.1
- [zustand](https://npm.io/package/zustand.md) ^5.0.7
- [@types/node](https://npm.io/package/@types/node.md) ^22.15.17
- [lucide-react](https://npm.io/package/lucide-react.md) ^1.25.0
- [tailwind-merge](https://npm.io/package/tailwind-merge.md) ^3.3.0
- [socket.io-client](https://npm.io/package/socket.io-client.md) ^4.8.1
- [use-context-selector](https://npm.io/package/use-context-selector.md) ^2.0.0

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 5.0.0 (latest) — 2026-08-31
- 5.0.1-rc.0 (rc) — 2026-10-02
- 1.4.17 (legacy) — 2026-04-17
- 5.0.0-rc.22 — 2026-08-26
- 5.0.0-rc.21 — 2026-08-24
- 5.0.0-rc.20 — 2026-08-21
- 5.0.0-rc.19 — 2026-08-20
- 5.0.0-rc.18 — 2026-08-20
- 5.0.0-rc.17 — 2026-08-18
- 5.0.0-rc.16 — 2026-08-17
- 5.0.0-rc.15 — 2026-08-17
- 5.0.0-rc.14 — 2026-08-12
- 5.0.0-rc.13 — 2026-08-10
- 5.0.0-rc.12 — 2026-08-10
- 5.0.0-rc.11 — 2026-08-07
- … 154 more at https://npm.io/package/@eduzz/ui-layout/versions

## README

# Eduzz UI: Layout Eduzz

Components de UI padrão das aplicações, aqui você vai encontrar:

* [Layout (Topbar, Sidebar, Content)](#layout)
* [useTheme](#usetheme)
* [App Loader](#app-loader)

# Layout

Estrutura padrão das aplicações.

## Importação

```ts
import Layout from '@eduzz/ui-layout';

// ou
import Layout from '@eduzz/ui-layout';
import Sidebar from '@eduzz/ui-layout/Sidebar';
import Topbar from '@eduzz/ui-layout/Topbar';
import Content from '@eduzz/ui-layout/Content';
```

## Estrutura base

```jsx
<Layout>
  <Layout.Topbar />
  <Layout.Sidebar />
  <Layout.Content />
</Layout>
```

## Desestruturando

Para simplificar a escrita do código, você pode desestruturar os componentes.

```jsx
import Layout from '@eduzz/ui-layout';

const { Sidebar, Topbar, Content } = Layout;
const { Item, Group, GroupWithGroupSwitcher } = Sidebar;

function CustomLayout() {
  return (
    <Layout>
      <Topbar {...topbarProps}>
        {...}
      </Topbar>

      <Sidebar {...sidebarProps}>
        {...}
      </Sidebar>

      <Content>
        {...}
      </Content>
    </Layout>
  );
}

export default CustomLayout;
```

## Exemplo

```jsx
import { NavLink, useLocation } from 'react-router-dom';

const { Sidebar, Topbar, Content } = Layout;
const { Item, Group, GroupWithGroupSwitcher } = Sidebar;

function MyComponent() {
  const location = useLocation();

  return (
    <Layout>
      <Topbar
        currentApplication='orbita'
        user={{
          name: 'Houston User',
          belt: 'Black Belt',
          avatar: 'https://picsum.photos/200',
          tag: 'unity'
        }}
      >
        <Topbar.UnitySupportChat token='...token gerado pelo servidor' />

        <Topbar.Action icon={<NotificationOutline size={25} />} label='Notificações' />
        <Topbar.Action icon={<InfoChatOutline size={25} />} />

        <Topbar.UserMenu>
          <Topbar.UserMenuItem>Meus Dados</Topbar.UserMenuItem>
          <Topbar.UserMenuItem>Minhas Compras</Topbar.UserMenuItem>

          <Topbar.UserMenuGroup label='Contas:'>
            <Topbar.UserMenuItem href='http://google.com' target='_blank'>
              John Doe
            </Topbar.UserMenuItem>
            <Topbar.UserMenuItem disabled>John Doe 2</Topbar.UserMenuItem>
          </Topbar.UserMenuGroup>

          <Topbar.UserMenuDivider />

          <Topbar.UserMenuItem>Sair</Topbar.UserMenuItem>
        </Topbar.UserMenu>
      </Topbar>

      <Sidebar currentLocation={location.pathname}>
        <Item href='/agendamento'>Resumo</Item>

        <GroupWithGroupSwitcher
            label='Integrações'
            options={[
              {
                id: 'whatsapp',
                label: 'Whatsapp',
                icon: <WhatsAppOutlined />,
                items: [
                  <Item key={'option-1-item-1'} id='sidebar-option-1-item-1'>
                    Templates
                  </Item>,
                  <Item key={'option-1-item-2'} id='sidebar-option-1-item-2'>
                    Configurações
                  </Item>
                ]
              },
              {
                id: 'email',
                label: 'Email',
                icon: <MailOutlined />,
                items: [
                  <Item key={'option-2-item-1'} id='sidebar-option-2-item-1'>
                    Layout
                  </Item>,
                  <Item key={'option-2-item-2'} id='sidebar-option-2-item-2'>
                    Templates
                  </Item>,
                  <Item key={'option-2-item-3'} id='sidebar-option-2-item-3'>
                    Configurações
                  </Item>
                ]
              }
            ]}
          />

        <Group label='Agendamento'>
          <Item as={NavLink} to='/agendamento'>
            Evento
          </Item>
          <Item as={NavLink} to='/agendamento'>
            MasterMind
          </Item>
          <Item as={NavLink} to='/agendamento'>
            Lançamento
          </Item>
        </Group>

        <Item disabled>Marketplace</Item>
      </Sidebar>

      <Content>{/*Your content here*/}</Content>
    </Layout>
  );
}
```

## Props

### Layout props

| prop                    | tipo                                   | obrigatório | padrão    | descrição                                                                        |
|-------------------------|----------------------------------------|-------------|-----------|----------------------------------------------------------------------------------|
| mode                    | `'light' \| 'dark'`                    | `false`     | `'light'` | Modo (Dark ou Light mode)                                                        |
| persistMode             | `boolean`                              | `false`     | `false`   | Faz o modo (Dark ou Light mode) persistir no cookie `eduzz-theme`                |
| acceptModeBySearchParam | `boolean`                              | `false`     | `false`   | Aceita receber `?eduzzMode=dark` na URL por exemplo, para definir o `mode`       |
| onModeChange            | `(newMode: 'light' \| 'dark') => void` | `false`     | -         | Função a ser executada toda vez que houver uma mudança de modo.                  |

### Topbar props

| prop               | tipo       | obrigatório | padrão | descrição                                                   |
|--------------------|------------|-------------|--------|-------------------------------------------------------------|
| logo               | `url`      | `false`     | -      | Url para o logo padrao.                                     |
| logoMobile         | `url`      | `false`     | -      | Url para o logo na versão mobile.                           |
| logoDarkMode       | `url`      | `false`     | -      | Url para o logo padrao no tema dark.                        |
| logoMobileDarkMode | `url`      | `false`     | -      | Url para o logo na versão mobile no tema dark.              |
| currentApplication | `string`   | `false`     | -      | Aplicação que está sendo usada, para marcar no menu de apps.|
| user               | `object`   | `false`     | -      | Se existe um usuário logado, sem ele não terá o menu User.  |
| disableApps        | `boolean`  | `false`     | `false`| Se verdadeiro esconde o menu de apps.                       |
| disableLogo        | `boolean`  | `false`     | `false`| Se verdadeiro esconde a logo.                               |
| startElement       | `ReactNode`| `false`     | -      | Elemento que será adicionado antes da logo                  |

### Topbar.Action props

| prop     | tipo        | obrigatório | padrão  | descrição                                            |
|----------|-------------|-------------|---------|------------------------------------------------------|
| icon     | `ReactNode` | `true`      | -       | Icone, tamanho ideal 25                              |
| label    | `string`    | `false`     | -       |                                                      |
| isActive | `boolean`   | `false`     | `false` | Se o icone deve manter o estado de pressionado/ativo |
| onClick  | `function`  | `false`     | -       |                                                      |

### Topbar.UserMenuItem props

| prop     | tipo        | obrigatório | padrão | descrição               |
|----------|-------------|-------------|--------|-------------------------|
| icon     | `ReactNode` | `true`      | -      | Icone, tamanho ideal 25 |
| children | `string`    | `false`     | -      | Deve ser uma string     |
| disabled | `boolean`   | `false`     | -      |                         |
| onClick  | `function`  | `false`     | -      |                         |

### Topbar.UserMenuGroup props

| prop     | tipo        | obrigatório | padrão | descrição |
|----------|-------------|-------------|--------|-----------|
| label    | `string`    | `true`      | -      |           |
| children | `ReactNode` | `true`      | -      |           |

### Topbar.UnitySupportChat props

| prop  | tipo     | obrigatório | padrão | descrição                                         |
|-------|----------|-------------|--------|---------------------------------------------------|
| token | `string` | `false`     | -      | Token gerado pelo servidor para uso do LiveHelper |


### Topbar.ModeSwitcher props

| prop               | tipo     | obrigatório | padrão | descrição                                                   |
|--------------------|----------|-------------|--------|-------------------------------------------------------------|
| tooltip| `string`| `false`| `'Tema'`|  Texto para o tooltip do botão. mode |
| badgeDot| `boolean`| `false`| `false`| Se um badgeDot deve ser adicionado ao botão .|

### Sidebar props

| prop            | tipo     | obrigatório | padrão | descrição                                |
|-----------------|----------|-------------|--------|------------------------------------------|
| currentLocation | `string` | `false`     | -      | Caminho de localização atual (pathname). |

### Sidebar.Item props

| prop     | tipo                | obrigatório | padrão  | descrição                                                                   |
|----------|---------------------|-------------|---------|-----------------------------------------------------------------------------|
| as       | `React.ElementType` | `false`     | -       | Componente que envolve o item.                                              |
| `any`    | `any`               | `false`     | -       | Qualquer prop que o `as` receba                                             |
| isActive | `boolean`           | `false`     | `false` | Irá usar o `currentLocation` fornecido para tentar ver se está ativo ou não |
| tabIndex | `number`            | `false`     | -       |                                                                             |
| disabled | `boolean`           | `false`     | -       |                                                                             |
| onClick  | `function`          | `false`     | -       |                                                                             |

### Sidebar.Group props

| prop          | tipo              | obrigatório | padrão | descrição                                    |
|---------------|-------------------|-------------|--------|----------------------------------------------|
| label         | `React.ReactNode` | `false`     | -      | -                                            |
| startExpanded | `boolean`         | `false`     | `true` | Se o grupo deve iniciar expandido por padrão |
| tabIndex      | `number`          | `false`     | -      |                                              |

### Sidebar.GroupWithGroupSwitcher props

| prop      | tipo                                        | obrigatório | padrão | descrição                                                                                             |
|-----------|---------------------------------------------|-------------|--------|-------------------------------------------------------------------------------------------------------|
| id        | `string`                                    | `false`     | -      | Identificador único para o elemento raiz (HTML `<li>`).                                             |
| label     | `ReactNode`                                 | `false`     | -      | Label ou título do grupo, exibido acima das opções do seletor.                                        |
| options   | `SidebarGroupWithGroupSwitcherOption[]`     | `true`      | -      | Array de opções que serão renderizadas no grupo. Cada opção define um conjunto de itens e atributos.   |
| className | `string`                                    | `false`     | -      | Classe CSS adicional para customização do componente.                                               |
| defaultOptionId | `string `                             | `false`     | -      | Valor padrão selecionado, caso não seja informado, será utilizada a primeira opção como padrão |
| onChangeOption | `(option: SidebarGroupWithGroupSwitcherOption) => void` | `false` | -      | Função que será chamada como callback ao alterar a opção |

### SidebarGroupWithGroupSwitcherOption

| prop  | tipo           | obrigatório | padrão | descrição                                                                              |
|-------|----------------|-------------|--------|----------------------------------------------------------------------------------------|
| id    | `string`       | `true`      | -      | Identificador único da opção.                                                          |
| label | `string`       | `true`      | -      | Texto que representa o rótulo da opção. Pode ser um nome ou título descritivo.         |
| icon  | `ReactNode`    | `false`     | -      | Elemento opcional que pode conter um ícone ou qualquer outro elemento visual.          |
| items | `ReactNode[]`  | `true`      | -      | Conjunto de itens (children) que serão renderizados quando a opção estiver selecionada. |


### Content props

| prop           | tipo      | obrigatório | padrão | descrição        |
|----------------|-----------|-------------|--------|------------------|
| disablePadding | `boolean` | `false`     | -      | Remove o padding |

## useTheme

Hook para ler e alterar o modo do tema (`light` / `dark`). Deve ser usado dentro de um `Layout`.

```tsx
import { useTheme } from '@eduzz/ui-layout';

function ThemeToggle() {
  const { theme, toggle, setTheme } = useTheme();

  return (
    <>
      <button onClick={toggle}>Tema atual: {theme}</button>
      <button onClick={() => setTheme('dark')}>Dark</button>
    </>
  );
}
```

# App Loader

Loader de aplicação padrão.

## Importação

```js
import AppLoader, { useAppLoader } from '@eduzz/ui-layout';
```

## Exemplo

Coloque no momento de `createRoot` e use o lazy para aparecer o loader antes da aplicação. Coloque o minimo de imports nesse arquivo para carregar o mais rapido possível.

```jsx
import { lazy } from 'react';
import { createRoot } from 'react-dom/client';
import AppLoader from '@eduzz/ui-layout'; 

const App = lazy(() => import('./App'));

createRoot(document.getElementById('app') as HTMLElement).render(
  <AppLoader>
    <App />
  </AppLoader>
);

// App.tsx
import { useEffect } from 'react';
import { useAppLoader } from '@eduzz/ui-layout';

function App() {
  const appLoader = useAppLoader();

  useEffect(() => {
    // Faça o que precisar ser feito e entao chame o `hide`
    appLoader.hide();
    // Caso queira aparecer novamente
    appLoader.show();
    // Se algo acontecer pode mostrar uma mensagem de erro
    appLoader.error(new Error(), () => console.log('Tente novamente'));
  }, []);

  return <div />
}
```

---
_Source: https://npm.io/package/@eduzz/ui-layout · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
