Team Switcher
A header dropdown to switch the active team. The official Laravel starter kit has no teams concept, so this is a complete Kinetix feature — but Kinetix does not own your Team model. It resolves the user's teams by convention and shares them (each with a ready-made switch URL) via the kinetix_teams Inertia prop; the component just visits that URL. So it works with whatever switch route your app already has.


Installation
Enable it and point the config at the relations/routes your app uses:
'team_switcher' => [
'enabled' => env('KINETIX_TEAM_SWITCHER_ENABLED', false),
// Relations on the user model.
'teams_relation' => 'teams', // → the user's teams
'current_relation' => 'currentTeam', // → the active team
// Team display label attribute.
'name_attribute' => 'name',
// Route to switch teams (receives the team's route key — slug when the
// model defines getRouteKeyName()). The starter-kit convention is below.
'switch_route' => env('KINETIX_TEAM_SWITCH_ROUTE', 'teams.switch'),
// Optional "New team" route.
'create_route' => env('KINETIX_TEAM_CREATE_ROUTE'),
],Kinetix reads auth()->user()->teams and ->currentTeam, builds a switch URL per team with route('teams.switch', $team->getRouteKey()), and shares the lot. You provide the switch route and the logic that sets the current team — Kinetix never touches your team pivot or tenancy.
Already have a switch route?
If your app (or your template) defines teams.switch — e.g. a controller calling $user->switchTeam($team) — you're done: set switch_route to its name and the switcher visits it.
The component
<script setup lang="ts">
import KinetixTeamSwitcher from '@/components/kinetix/KinetixTeamSwitcher.vue';
</script>
<template>
<KinetixTeamSwitcher />
</template>It shows the current team with a Users icon; the dropdown lists every team (the active one marked), plus a New team entry when create_route is set. Selecting a team visits its switch URL; the already-active team is a no-op.
useKinetixTeams() exposes { teams, current, createUrl, switchTeam } for a custom UI. Strings are localized (teams_switch, teams_select, teams_new; en/es/fr/pt).
Building team-aware links
The same composable is how you link between your own pages in a multitenant app — teamUrl() prefixes a path with the active team's segment:
<script setup lang="ts">
import { Link } from '@inertiajs/vue3';
import { useKinetixTeams } from '@/composables/useKinetixTeams';
const { teamUrl, currentTeamKey } = useKinetixTeams();
</script>
<template>
<Link :href="teamUrl('/projects')">Projects</Link> <!-- /acme/projects -->
</template>teamUrl(path) | The path prefixed with the active team segment; unchanged when teams are off, and never double-prefixed |
currentTeamKey | The raw segment ('acme'), or null when teams are off |
Two reasons to prefer it over hand-built strings:
- The segment is the team's route key (
getRouteKey()— a slug or uuid when the model defines one), not theidyou get fromcurrent. Interpolatingcurrent.idproduces URLs that 404 as soon as teams are slug-routed. - It is driven by the server's resolution of the current request, so a link rendered on
/beta/...points atbetaeven when the user's storedcurrentTeamis something else.
Unlike the switcher, linking only needs kinetix.teams — team_switcher.enabled is not required.
Shared prop
kinetix_teams is shared on every Inertia response:
{
enabled: boolean,
teams: { id, name, url: string | null, current: boolean }[],
current: { id, name } | null,
createUrl: string | null,
}url is null when the configured switch route doesn't exist, so the switcher degrades gracefully. The payload is empty (enabled: false) for guests or when the feature is off.

