React 62 ⚛️ Protected and Nested Routes
A route that renders a component is a route that anyone can visit. Real applications need more: a page that only authenticated users can see, a section that only administrators can enter, a nested layout that wraps a group of related pages. React Router provides the building blocks for all three. A protected route wraps a component in a check and redirects if the check fails. A nested route shares a layout across a group of child routes. The two combine into a tree where the layout is rendered once, the protection is applied at the right level, and the children are the pages the user actually sees.
Key point: A protected route is not a security boundary. It is a client-side check that redirects unauthenticated users. A determined user can bypass it by manipulating the client. The server must enforce the real authorization on every API call. The protected route is a user-experience feature, not a security feature.
Why protected and nested routes exist
The authentication problem. Some pages require the user to be logged in. The dashboard, the settings, the checkout. The page cannot render without the user’s data, and the API returns 401 if the user is not authenticated. The protected route checks the authentication before the page renders and redirects to the login page if the check fails.
The authorization problem. Some pages require a specific role. The admin panel requires the admin role, the billing page requires the owner role. The protected route checks the role and redirects to a forbidden page if the check fails.
The layout problem. A group of related pages shares a header, a sidebar, and a footer. The layout should be rendered once and remain mounted across the navigations between the child pages. The nested route structure is the mechanism.
The code organization problem. The route configuration is a tree. The nesting reflects the URL hierarchy, the component hierarchy, and the layout hierarchy. The structure is the documentation.
The redirect problem. The unauthenticated user who tries to visit the dashboard should be redirected to the login page, and after the login, the user should return to the dashboard. The protected route and the login page cooperate to produce the return.
The role problem. The user who is authenticated but lacks the required role should be redirected to a different page, not to the login page. The role check produces the “forbidden” page, and the login check produces the login redirect.
The composition problem. A route can be both protected and nested. The parent route checks the authentication, and the child routes render inside the layout. The two features are independent, and they compose.
a. The protected route
A protected route wraps a component in an authentication check. The check runs on every render, and the component is rendered only if the check passes.
The basic protected route
import { Navigate, useLocation } from 'react-router-dom';
function ProtectedRoute({ children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
The component reads the authentication state, and the Navigate redirects to the login page if the user is not authenticated. The location is passed in the state, so the login page can redirect back to the original page.
The usage
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
The Dashboard is wrapped in the ProtectedRoute. The route matches, the protected route checks the authentication, and the dashboard renders only if the check passes.
The route-level protection
The protection can be applied at the route configuration level with a layout route.
<Routes>
<Route element={<ProtectedRoute><Outlet /></ProtectedRoute>}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile" element={<Profile />} />
</Route>
</Routes>
The parent route has no path, and its element is the ProtectedRoute that renders the <Outlet />. The child routes are all protected. A new child route is protected by being added to the group.
The login redirect with the return
function LoginPage() {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname ?? '/dashboard';
async function handleLogin(credentials) {
await login(credentials);
navigate(from, { replace: true });
}
return <LoginForm onSubmit={handleLogin} />;
}
The login page reads the from from the state and navigates there after the authentication. The replace: true prevents the user from returning to the login page with the back button.
The role-based protection
The protection can check the user’s role in addition to the authentication.
function RoleRoute({ role, children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
if (user.role !== role) {
return <Navigate to="/forbidden" replace />;
}
return children;
}
The component checks the authentication first and the role second. The unauthenticated user goes to the login page, and the authenticated user with the wrong role goes to the forbidden page.
The permission-based protection
The protection can check a permission or a feature flag.
function PermissionRoute({ permission, children }) {
const { user, permissions } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
if (!permissions.includes(permission)) {
return <Navigate to="/forbidden" replace />;
}
return children;
}
The component checks the permission list. The pattern is the same as the role check, with a different predicate.
The nested protection
A protected route can contain another protected route. The outer check runs first, and the inner check runs only if the outer passes.
<Route element={<ProtectedRoute><Outlet /></ProtectedRoute>}>
<Route path="/admin" element={
<RoleRoute role="admin">
<AdminLayout />
</RoleRoute>
}>
<Route index element={<AdminDashboard />} />
<Route path="users" element={<AdminUsers />} />
</Route>
</Route>
The outer ProtectedRoute checks the authentication, and the inner RoleRoute checks the admin role. The unauthenticated user goes to the login page, and the authenticated non-admin goes to the forbidden page.
The loading state
The authentication check may be asynchronous. The useAuth hook returns a loading state while the token is verified.
function ProtectedRoute({ children }) {
const { user, loading } = useAuth();
const location = useLocation();
if (loading) {
return <LoadingSpinner />;
}
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
The LoadingSpinner renders while the check is in progress. The redirect happens only after the check completes.
The <Navigate> vs the useNavigate
The <Navigate> component is the declarative form and is used inside a render. The useNavigate hook is the imperative form and is used inside an effect or an event handler. The protected route uses the <Navigate> because the redirect is part of the render.
b. The nested routes
A nested route is a route inside another route. The parent route renders a layout and an <Outlet>, and the child route renders inside the outlet.
The nested route configuration
<Routes>
<Route path="/" element={<RootLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="teams" element={<TeamsLayout />}>
<Route index element={<TeamsList />} />
<Route path=":teamId" element={<TeamDetail />} />
</Route>
</Route>
</Routes>
The RootLayout renders the global header and the <Outlet>. The TeamsLayout renders the teams-specific navigation and another <Outlet>. The TeamDetail renders the specific team.
The layout component
import { Outlet, NavLink } from 'react-router-dom';
function RootLayout() {
return (
<div className="app">
<header>
<nav>
<NavLink to="/">Home</NavLink>
<NavLink to="/about">About</NavLink>
<NavLink to="/teams">Teams</NavLink>
</nav>
</header>
<main>
<Outlet />
</main>
<footer>© 2026</footer>
</div>
);
}
The <Outlet> is the placeholder for the matched child route.
The index route
The index route renders at the parent’s URL when no other child matches.
<Route path="/" element={<RootLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
</Route>
The URL / renders RootLayout with Home in the outlet. The URL /about renders RootLayout with About in the outlet.
The dynamic segment
A path segment that starts with : is a dynamic segment.
<Route path="teams/:teamId" element={<TeamDetail />} />
The useParams hook reads the value.
function TeamDetail() {
const { teamId } = useParams();
return <h1>Team: {teamId}</h1>;
}
The nested layout
A nested layout is a route that renders its own <Outlet>.
function TeamsLayout() {
return (
<div className="teams">
<aside>
<NavLink to="/teams">All Teams</NavLink>
<NavLink to="/teams/firebirds">Firebirds</NavLink>
</aside>
<section>
<Outlet />
</section>
</div>
);
}
The TeamsLayout renders the sidebar and the outlet. The child route renders in the outlet.
The layout persistence
The layout is not remounted when the child route changes. The state, the scroll position, and the DOM are preserved across the navigations between the child routes.
// Navigating from /teams/firebirds to /teams/dolphins:
// <RootLayout> stays mounted.
// <TeamsLayout> stays mounted.
// <TeamDetail> remounts with a new teamId.
The splat route
A splat route matches any remaining segments.
<Route path="files/*" element={<FileViewer />} />
The useParams hook reads the splat value.
function FileViewer() {
const { '*': splat } = useParams();
return <p>File: {splat}</p>;
}
The nested index route
An index route can be nested inside a nested layout.
<Route path="teams" element={<TeamsLayout />}>
<Route index element={<TeamsList />} />
<Route path=":teamId" element={<TeamDetail />} />
</Route>
The URL /teams renders TeamsLayout with TeamsList in the outlet. The URL /teams/firebirds renders TeamsLayout with TeamDetail in the outlet.
The pathless layout route
A route without a path renders a layout for a group of children.
<Route element={<AuthLayout />}>
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Route>
The AuthLayout renders the authentication-specific layout and the <Outlet>. The children share the layout without sharing the path prefix.
c. The combination
The protected route and the nested route compose. The layout is the outer structure, and the protection is applied at the right level.
The protected layout
function ProtectedLayout() {
const { user, loading } = useAuth();
const location = useLocation();
if (loading) return <LoadingSpinner />;
if (!user) return <Navigate to="/login" state={{ from: location }} replace />;
return <Outlet />;
}
The layout checks the authentication and renders the outlet. The children are all protected.
The route configuration
<Routes>
<Route path="/" element={<PublicLayout />}>
<Route index element={<Home />} />
<Route path="login" element={<Login />} />
<Route path="about" element={<About />} />
</Route>
<Route element={<ProtectedLayout />}>
<Route path="dashboard" element={<Dashboard />} />
<Route path="settings" element={<SettingsLayout />}>
<Route index element={<SettingsProfile />} />
<Route path="account" element={<SettingsAccount />} />
<Route path="billing" element={<SettingsBilling />} />
</Route>
</Route>
</Routes>
The PublicLayout renders the public pages. The ProtectedLayout checks the authentication and renders the protected pages. The SettingsLayout renders the settings navigation and the settings pages.
The role-based combination
<Route element={<ProtectedLayout />}>
<Route path="dashboard" element={<Dashboard />} />
<Route element={<RoleLayout role="admin" />}>
<Route path="admin/users" element={<AdminUsers />} />
<Route path="admin/settings" element={<AdminSettings />} />
</Route>
</Route>
The RoleLayout checks the role and renders the outlet. The admin routes are nested inside the protected layout and the role layout.
The unauthenticated flow
- The user visits
/dashboard. - The
ProtectedLayoutchecks the authentication. - The user is not authenticated, and the
Navigateredirects to/loginwith thefromstate. - The user logs in.
- The login page reads the
fromand navigates back to/dashboard. - The
ProtectedLayoutchecks the authentication and renders the dashboard.
The unauthorized flow
- The user visits
/admin/users. - The
ProtectedLayoutchecks the authentication. The user is authenticated. - The
RoleLayoutchecks the role. The user is not an admin. - The
Navigateredirects to/forbidden. - The forbidden page renders.
The nested redirect
The redirect from a nested route goes to the top-level route, not to the parent.
function TeamDetail() {
const { teamId } = useParams();
const team = useTeam(teamId);
if (!team) return <Navigate to="/teams" replace />;
return <h1>{team.name}</h1>;
}
The redirect goes to /teams, which is the parent route.
The composition table
| Combination | Structure |
|---|---|
| Protected page | <ProtectedRoute><Page /></ProtectedRoute> |
| Protected group | <Route element={<ProtectedLayout />}>... |
| Nested layout | <Route element={<Layout />}>... |
| Role-protected | <Route element={<RoleLayout role="admin" />}>... |
| Public + protected | Two top-level layout routes |
Complete Example Session
// ============================================
// PART 1: THE BASIC PROTECTED ROUTE
// ============================================
import { Navigate, useLocation } from 'react-router-dom';
function ProtectedRoute({ children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
// ============================================
// PART 2: THE USAGE
// ============================================
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
// ============================================
// PART 3: THE ROUTE-LEVEL PROTECTION
// ============================================
function ProtectedLayout() {
const { user, loading } = useAuth();
const location = useLocation();
if (loading) return <LoadingSpinner />;
if (!user) return <Navigate to="/login" state={{ from: location }} replace />;
return <Outlet />;
}
<Routes>
<Route element={<ProtectedLayout />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile" element={<Profile />} />
</Route>
</Routes>
// ============================================
// PART 4: THE ROLE-BASED PROTECTION
// ============================================
function RoleRoute({ role, children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
if (user.role !== role) {
return <Navigate to="/forbidden" replace />;
}
return children;
}
// ============================================
// PART 5: THE LOGIN REDIRECT WITH THE RETURN
// ============================================
function LoginPage() {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname ?? '/dashboard';
async function handleLogin(credentials) {
await login(credentials);
navigate(from, { replace: true });
}
return <LoginForm onSubmit={handleLogin} />;
}
// ============================================
// PART 6: THE NESTED ROUTES
// ============================================
<Routes>
<Route path="/" element={<RootLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="teams" element={<TeamsLayout />}>
<Route index element={<TeamsList />} />
<Route path=":teamId" element={<TeamDetail />} />
</Route>
</Route>
</Routes>
// ============================================
// PART 7: THE LAYOUT COMPONENT
// ============================================
function RootLayout() {
return (
<div>
<Header />
<main><Outlet /></main>
<Footer />
</div>
);
}
function TeamsLayout() {
return (
<div className="teams">
<Sidebar />
<section><Outlet /></section>
</div>
);
}
// ============================================
// PART 8: THE COMBINED CONFIGURATION
// ============================================
<Routes>
<Route path="/" element={<PublicLayout />}>
<Route index element={<Home />} />
<Route path="login" element={<Login />} />
<Route path="about" element={<About />} />
</Route>
<Route element={<ProtectedLayout />}>
<Route path="dashboard" element={<Dashboard />} />
<Route path="settings" element={<SettingsLayout />}>
<Route index element={<SettingsProfile />} />
<Route path="account" element={<SettingsAccount />} />
</Route>
<Route element={<RoleRoute role="admin"><Outlet /></RoleRoute>}>
<Route path="admin/users" element={<AdminUsers />} />
</Route>
</Route>
</Routes>
// ============================================
// PART 9: THE NESTED REDIRECT
// ============================================
function TeamDetail() {
const { teamId } = useParams();
const team = useTeam(teamId);
if (!team) return <Navigate to="/teams" replace />;
return <h1>{team.name}</h1>;
}
// ============================================
// PART 10: THE COMPLETE PATTERN
// ============================================
// 1. Wrap the page in <ProtectedRoute> for the page-level protection.
// 2. Use a pathless layout route for the group-level protection.
// 3. Use the state to pass the original location to the login page.
// 4. Use the role check for the authorization.
// 5. Use the nested route for the shared layout.
// 6. Use the index route for the default child.
// 7. Use the dynamic segment for the parameter.
// 8. The layout persists across the child navigations.
// 9. The protected route is a client-side check, not a security boundary.
// 10. The server enforces the real authorization.
The ten parts showed the basic protected route, the usage, the route-level protection, the role-based protection, the login redirect, the nested routes, the layout component, the combined configuration, the nested redirect, and the complete pattern.
Quick Reference
The Protected Route Forms
| Form | Scope |
|---|---|
<ProtectedRoute><Page /></ProtectedRoute> | A single page |
<Route element={<ProtectedLayout />}> | A group of pages |
<RoleRoute role="admin"> | A role-protected page |
<PermissionRoute permission="..."> | A permission-protected page |
The Nested Route Forms
| Form | Purpose |
|---|---|
<Route path="/" element={<Layout />}> | The layout route |
<Route index element={<Home />} /> | The default child |
<Route path=":id" element={<Detail />} /> | The dynamic segment |
<Route path="*" element={<NotFound />} /> | The splat route |
<Route element={<Layout />}> | The pathless layout |
The Layout Components
| Component | Renders |
|---|---|
RootLayout | The global header and footer |
PublicLayout | The public page layout |
ProtectedLayout | The authentication check and the outlet |
SettingsLayout | The settings navigation and the outlet |
The Redirect
| Redirect | Use |
|---|---|
Navigate to="/login" | The unauthenticated user |
Navigate to="/forbidden" | The unauthorized user |
Navigate to="/teams" | The missing resource |
Navigate to="/404" | The unmatched URL |
The Auth Hook
| Property | Purpose |
|---|---|
user | The current user or null |
loading | The authentication check in progress |
role | The user’s role |
permissions | The user’s permissions |
Best Practices
✅ Do This:
// Use the protected route for the authentication check.
<ProtectedRoute><Dashboard /></ProtectedRoute> // ✅
// Use the pathless layout route for the group.
<Route element={<ProtectedLayout />}>...</Route> // ✅
// Pass the original location to the login page.
<Navigate to="/login" state={{ from: location }} replace /> // ✅
// Use the role check for the authorization.
if (user.role !== 'admin') return <Navigate to="/forbidden" replace />; // ✅
// Use the nested route for the shared layout.
<Route path="teams" element={<TeamsLayout />}>...</Route> // ✅
// Use the index route for the default child.
<Route index element={<TeamsList />} /> // ✅
// Enforce the authorization on the server.
// The client-side check is not a security boundary. // ✅
❌ Don’t Do This:
// Don't rely on the client-side check for the security.
// The server must enforce the authorization. // ❌
// Don't forget the loading state.
if (!user) return <Navigate to="/login" />; // ❌ Redirects during the check
// Don't lose the original location.
return <Navigate to="/login" />; // ❌ The user loses the destination
// Don't redirect the unauthorized user to the login.
if (user.role !== 'admin') return <Navigate to="/login" />; // ❌ The user is already logged in
// Don't nest the protected route inside the public layout.
<PublicLayout><ProtectedRoute>...</ProtectedRoute></PublicLayout> // ❌
// Don't forget the outlet in the layout.
function Layout() { return <div>...</div>; } // ❌ The children never render
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Redirect loop | The login page is protected | Exclude the login from the check |
| Lost destination | No state: { from } | Pass the location |
| Flash of the protected content | No loading state | Render the spinner |
| Children not rendering | No <Outlet> | Add the outlet |
| Unauthorized goes to login | The role check redirects to login | Redirect to /forbidden |
| Role check bypassed | Client-side only | Enforce on the server |
| Nested redirect to the wrong level | The relative path | Use the absolute path |
Real-World Examples
1. Basic Protected Route
<ProtectedRoute><Dashboard /></ProtectedRoute>
2. Protected Layout
<Route element={<ProtectedLayout />}>
<Route path="/dashboard" element={<Dashboard />} />
</Route>
3. Role Route
<RoleRoute role="admin"><AdminPanel /></RoleRoute>
4. Login Redirect
<Navigate to="/login" state={{ from: location }} replace />
5. Post-Login Return
navigate(from, { replace: true });
6. Nested Layout
<Route path="teams" element={<TeamsLayout />}>
<Route index element={<TeamsList />} />
</Route>
7. Index Route
<Route index element={<Home />} />
8. Dynamic Segment
<Route path=":teamId" element={<TeamDetail />} />
9. Pathless Layout
<Route element={<AuthLayout />}>
<Route path="/login" element={<Login />} />
</Route>
10. The Nested Redirect
if (!team) return <Navigate to="/teams" replace />;
Visual
The Route Tree
┌────────────────────────────────────────────────────────────┐
│ THE ROUTE TREE │
│ │
│ / │
│ └── PublicLayout │
│ ├── index → Home │
│ ├── login → Login │
│ └── about → About │
│ │
│ (pathless) │
│ └── ProtectedLayout │
│ ├── dashboard → Dashboard │
│ ├── settings → SettingsLayout │
│ │ ├── index → SettingsProfile │
│ │ └── account → SettingsAccount │
│ └── admin → RoleLayout (admin) │
│ └── users → AdminUsers │
│ │
│ Each level renders its layout and the outlet. │
└────────────────────────────────────────────────────────────┘
The Protected Flow
┌────────────────────────────────────────────────────────────┐
│ THE PROTECTED FLOW │
│ │
│ 1. User visits /dashboard │
│ 2. ProtectedLayout checks the auth │
│ 3. Not authenticated → Navigate to /login │
│ state: { from: '/dashboard' } │
│ 4. User logs in │
│ 5. Login page reads the from │
│ 6. Navigate to /dashboard with replace │
│ 7. ProtectedLayout checks the auth │
│ 8. Authenticated → renders the dashboard │
│ │
│ The state carries the original destination. │
└────────────────────────────────────────────────────────────┘
The Nested Layout
┌────────────────────────────────────────────────────────────┐
│ THE NESTED LAYOUT │
│ │
│ URL: /teams/firebirds │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ <RootLayout> │ │
│ │ <Header /> │ │
│ │ <Outlet> │ │
│ │ <TeamsLayout> │ │
│ │ <Sidebar /> │ │
│ │ <Outlet> │ │
│ │ <TeamDetail teamId="firebirds" /> │ │
│ │ </Outlet> │ │
│ │ </TeamsLayout> │ │
│ │ </Outlet> │ │
│ │ <Footer /> │ │
│ │ </RootLayout> │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ The layout persists across the child navigations. │
└────────────────────────────────────────────────────────────┘
The Redirect Comparison
┌────────────────────────────────────────────────────────────┐
│ THE REDIRECT COMPARISON │
│ │
│ UNAUTHENTICATED │
│ ┌──────────────────────────────────────────────────┐ │
│ │ user === null │ │
│ │ → Navigate to /login │ │
│ │ → state: { from: location } │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ UNAUTHORIZED │
│ ┌──────────────────────────────────────────────────┐ │
│ │ user.role !== 'admin' │ │
│ │ → Navigate to /forbidden │ │
│ │ → (not to /login, the user is authenticated) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ The two cases have different destinations. │
└────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Protected route | A component that checks the authentication |
<Navigate> | The declarative redirect |
state: { from } | The original location |
| Role route | A component that checks the role |
| Nested route | A route inside another route |
<Outlet> | The child route placeholder |
| Index route | The default child |
| Dynamic segment | The :id path segment |
| Pathless layout | A layout without a path |
| Layout persistence | The layout stays mounted |
Key takeaways:
- A protected route checks the authentication and redirects if the check fails. The component reads the auth state and renders the
<Navigate>to the login page. The state carries the original location, so the user can return after the login. - A role route checks the authorization in addition to the authentication. The unauthenticated user goes to the login, and the authenticated user with the wrong role goes to the forbidden page. The two cases have different destinations.
- The route-level protection uses a pathless layout route. The parent route has no path, and its element is the protected layout that renders the
<Outlet>. The children are all protected. - The nested route renders a layout and an
<Outlet>. The layout is rendered once and stays mounted across the navigations between the child routes. The state, the scroll position, and the DOM are preserved. - The index route renders at the parent’s URL. It is the default child when no other child matches. The URL
/teamsrenders the teams layout with the teams list. - The dynamic segment captures the URL value. The
:teamIdsegment is read with theuseParamshook. The value is a string that the component parses. - The protected route is a client-side check, not a security boundary. The client-side check is a user-experience feature. The server must enforce the real authorization on every API call.
- The nested redirect goes to the top-level route. A component that cannot find the resource redirects to the parent route, not to a sibling. The absolute path is the safe form.
Remember: The protected route and the nested route are the two building blocks of the application’s route tree. The protected route checks the authentication and the authorization, and it redirects to the login or the forbidden page. The nested route renders the shared layout and the <Outlet>, and the layout stays mounted across the child navigations. The two compose into a tree where the layout is the outer structure, the protection is applied at the right level, and the children are the pages the user sees. The result is an application where the public pages are open, the protected pages check the authentication, the role pages check the authorization, and the shared layouts wrap the groups.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!