1

I'm trying to make use of Mantine's App shell (https://mantine.dev/core/app-shell/) in React Router to have it enabled on only specific routes.

How is it possible to implement this.

Usually, to display a component I would to the following, for example:

<Route element={<SidebarLayout {...{ inactive, setInactive }} />}>
                <Route path="/" element={<Main />} />

But in this case, I got way more code (based on the example in the docs) - I'm planning to add a component inside this <AppShell> Component (please look all the way down):

<AppShell
      styles={{
        main: {
          background:
            theme.colorScheme === "dark"
              ? theme.colors.dark[8]
              : theme.colors.gray[0],
        },
      }}
      navbarOffsetBreakpoint="sm"
      asideOffsetBreakpoint="sm"
      navbar={
        <Navbar
          p="md"
          hiddenBreakpoint="sm"
          hidden={!opened}
          width={{ sm: 200, lg: 300 }}
        >
          <Text>Application navbar</Text>
        </Navbar>
      }
      aside={
        <MediaQuery smallerThan="sm" styles={{ display: "none" }}>
          <Aside p="md" hiddenBreakpoint="sm" width={{ sm: 200, lg: 300 }}>
            <Text>Application sidebar</Text>
          </Aside>
        </MediaQuery>
      }
      footer={
        <Footer height={60} p="md">
          Application footer
        </Footer>
      }
      header={
        <Header height={70} p="md">
          <div
            style={{ display: "flex", alignItems: "center", height: "100%" }}
          >
            <MediaQuery largerThan="sm" styles={{ display: "none" }}>
              <Burger
                opened={opened}
                onClick={() => setOpened((o) => !o)}
                size="sm"
                color={theme.colors.gray[6]}
                mr="xl"
              />
            </MediaQuery>

            <Text>Application header</Text>
          </div>
        </Header>
      }
    >
      <Text>Resize app to see responsive navbar in action</Text> <-- PLANNING TO ADD COMPONENT HERE BASED ON ROUTE
    </AppShell>

How can I integrate this whole thing in React Router?

2
  • 1
    Does Outlet suit your needs? reactrouter.com/docs/en/v6/components/outlet Commented Aug 5, 2022 at 15:50
  • @user4980215 Yes, that's actually what I was looking for. Thank you! Cheers. Commented Aug 5, 2022 at 17:28

2 Answers 2

4

As the "SidebarLayout" name implies, you are asking how to implement what is called a layout route. Layout routes generally render some common logic and UI elements/components, and an Outlet component for nested routes to render their content into. You generally render the Outlet component where you'd normally render the children prop.

Example:

Render an Outlet below the Text component.

<AppShell
  ...
>
  <Text>Resize app to see responsive navbar in action</Text>
  <Outlet /> // <-- render Outlet here for nested routes
</AppShell>

Usage:

<Routes>
  <Route element={<SidebarLayout {...{ inactive, setInactive }} />}>
    <Route path="/" element={<Main />} />
    ... other routes with SidebarLayout ...
  </Route>

  ... other routes w/o SidebarLayout ...
</Routes>
Sign up to request clarification or add additional context in comments.

Comments

0

This can be done in 2 ways:

Loading AppShell in a wrapper function:

By loading the AppShell component inside a wrapper function, you can wrap your sub-components by passing them based on the route path.

  1. You need to create a separate wrapper component, let's call it withAppShell component, now you can load it as follows:
export const withAppShell = (ChildComponent) => 
    ( 
        <AppShell ... // App Shell code start
        <ChildComponent /> // the part where you wish to load your child component
        </AppShell> // App Shell code end
    )
  1. To use it, first import, then:
withAppShell(ChildComponent);

Loading AppShell in a wrapper component:

Feels similar to the first one, but is not-

  1. Create the component:
export const AppShellWrapper = ({children}) => 
    (
        <AppShell ... //start
        {children}
        </AppShell> //end
    )
  1. Using it, first import, then:
<AppShellWrapper>
   <ChildComponent />
</AppShellWrapper>

2 Comments

I prefer the second method btw, because you can manage it much easily and can have more than one component inside the wrapper without having to create a separate component for that use-case.
It looks like you are trying to create a Higher Order Component with the first example, but it neglects to pass the props object through to the AppShell and decorated Component. It's a regular function so it should be called withAppShell instead of WithAppShell like a React component. E.G. const withAppShell = Component => ({ inactive, setInactive, ...props }) => (<AppShell {...{ inactive, setInactive }}><Component {...props} /></AppShell>);. Neither of these solutions lend themselves to working nicely with a group of nested routes though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.