Teardown

File-Based Routing

Route file conventions and naming patterns.

Routes are defined by creating files in your src/_routes/ directory. The file path determines the URL path.

File Naming Conventions

Basic Routes

FileURL Path
index.tsx/
about.tsx/about
settings.tsx/settings
users/index.tsx/users
users/profile.tsx/users/profile

Dynamic Routes

Use brackets for dynamic segments:

FileURL PathExample
[id].tsx/:id/123
users/[userId].tsx/users/:userId/users/abc
posts/[postId]/comments.tsx/posts/:postId/comments/posts/5/comments

Optional Parameters

Use double brackets for optional segments:

FileURL PathMatches
[[id]].tsx/:id?/ or /123
users/[[tab]].tsx/users/:tab?/users or /users/settings

Catch-All Routes

Use spread syntax for catch-all segments:

FileURL PathMatches
[...slug].tsx/*/a, /a/b, /a/b/c
docs/[...path].tsx/docs/*/docs/intro, /docs/api/hooks

Special Files

Layout Files (_layout.tsx)

Define navigator configuration for a directory:

// src/_routes/_layout.tsx
import { defineLayout } from "@teardown/navigation";

export default defineLayout({
  type: "stack",
  screenOptions: {
    headerShown: true,
  },
});

Screen Files

All other .tsx files define screens:

// src/_routes/settings.tsx
import { defineScreen } from "@teardown/navigation";

function SettingsScreen() {
  return <View><Text>Settings</Text></View>;
}

export default defineScreen({
  component: SettingsScreen,
  options: { title: "Settings" },
});

Route Groups

Use parentheses to group routes without affecting the URL:

src/_routes/
├── (auth)/
│   ├── _layout.tsx     # Auth-specific layout
│   ├── login.tsx       # /login
│   └── register.tsx    # /register
├── (main)/
│   ├── _layout.tsx     # Main app layout (tabs)
│   ├── home.tsx        # /home
│   └── profile.tsx     # /profile
└── _layout.tsx         # Root layout

Route groups are useful for:

  • Applying different layouts to different sections
  • Organizing related routes together
  • Keeping the URL structure clean

Directory Structure Examples

Simple App

src/_routes/
├── _layout.tsx      # Stack navigator
├── index.tsx        # /
├── about.tsx        # /about
└── settings.tsx     # /settings

App with Nested Routes

src/_routes/
├── _layout.tsx           # Root stack
├── index.tsx             # /
├── users/
│   ├── _layout.tsx       # Users stack
│   ├── index.tsx         # /users
│   └── [userId].tsx      # /users/:userId
└── settings/
    ├── index.tsx         # /settings
    ├── account.tsx       # /settings/account
    └── notifications.tsx # /settings/notifications

App with Tabs

src/_routes/
├── _layout.tsx           # Root stack
├── (tabs)/
│   ├── _layout.tsx       # Tab navigator
│   ├── home.tsx          # /home (tab)
│   ├── search.tsx        # /search (tab)
│   └── profile.tsx       # /profile (tab)
└── settings.tsx          # /settings (modal)

Defining Screens

Basic Screen

import { defineScreen } from "@teardown/navigation";
import { View, Text } from "react-native";

function MyScreen() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default defineScreen({
  component: MyScreen,
});

Screen with Options

import { defineScreen } from "@teardown/navigation";

export default defineScreen({
  component: ProfileScreen,
  options: {
    title: "Profile",
    headerShown: true,
    presentation: "modal",
  },
});

Screen with Dynamic Options

import { defineScreen } from "@teardown/navigation";

export default defineScreen({
  component: UserScreen,
  options: ({ route }) => ({
    title: `User ${route.params?.userId}`,
  }),
});

Screen with Event Listeners

import { defineScreen } from "@teardown/navigation";

export default defineScreen({
  component: FormScreen,
  options: { title: "Edit" },
  listeners: {
    beforeRemove: (e) => {
      // Prevent leaving if form is dirty
      if (formIsDirty) {
        e.preventDefault();
        // Show confirmation dialog
      }
    },
  },
});

Auto-Generated Templates

When autoTemplate is enabled (default), creating a new file automatically populates it with a template:

// Auto-generated when you create src/_routes/new-page.tsx
import { View, Text, StyleSheet } from "react-native";
import { defineScreen } from "@teardown/navigation";

function NewPageScreen() {
  return (
    <View style={styles.container}>
      <Text>New Page</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
});

export default defineScreen({
  component: NewPageScreen,
  options: {
    title: "New Page",
  },
});

Next Steps