# Large title header

> An iOS large title that collapses into a compact bar as the content scrolls: the titles cross-fade, the bar fades in, the title stretches when pulled past the top and a half-finished collapse settles on either state.

- Type: Component (navigation)
- Access: Free, open source (MIT)
- Page: https://goodui.dev/native/components/large-title-header
- Markdown: https://goodui.dev/native/components/large-title-header.md
- Registry item: https://goodui.dev/native/r/large-title-header.json
- Dependencies: react-native-reanimated, react-native-svg
- Keywords: react native large title, collapsing header, ios large title header expo, animated scroll header, header with search bar, navigation bar title fade

## When to use

- Top-level screens with a list: inbox, workouts, accounts, settings.
- Screens that need a search field under the title and one to three trailing actions.

## When not to use

- Detail screens deep in a stack: the navigator's standard header is quieter.
- Screens without scrolling content: a static title is enough.
- Searching as the main task of the screen: use search-bar on its own.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add https://goodui.dev/native/r/large-title-header.json
npx expo install --fix
```

The component lands in `components/goodui-native/large-title-header/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
import { Stack, router } from "expo-router";
import { LargeTitleScrollView } from "@/components/goodui-native/large-title-header/large-title-header";

export default function Inbox() {
  const [query, setQuery] = useState("");
  return (
    <>
      <Stack.Screen options={{ headerShown: false }} />
      <LargeTitleScrollView
        title="Inbox"
        subtitle="4 unread"
        onBack={() => router.back()}
        search={{ value: query, onChangeText: setQuery, placeholder: "Search mail" }}
        actions={[{ key: "compose", accessibilityLabel: "New message", icon: (p) => <PencilIcon {...p} />, onPress: compose }]}
      >
        {messages.map((m) => <MessageRow key={m.id} message={m} />)}
      </LargeTitleScrollView>
    </>
  );
}
```

## Examples

### Your own list (FlatList)

```tsx
const scrollY = useSharedValue(0);
const distance = useSharedValue(52);
const onScroll = useAnimatedScrollHandler((e) => {
  scrollY.value = e.contentOffset.y;
});
const insets = useInsets();

<View style={{ flex: 1 }}>
  <Animated.FlatList
    data={rows}
    onScroll={onScroll}
    scrollEventThrottle={16}
    contentContainerStyle={{ paddingTop: insets.top + 44 }}
    ListHeaderComponent={<LargeTitle title="Accounts" scrollY={scrollY} collapseDistance={distance} />}
    renderItem={renderRow}
  />
  <LargeTitleHeader title="Accounts" scrollY={scrollY} collapseDistance={distance} />
</View>
```

### Share the scroll with a hiding tab bar

```tsx
const scrollY = useSharedValue(0);

<View style={{ flex: 1 }}>
  <LargeTitleScrollView title="Workouts" scrollY={scrollY} contentContainerStyle={{ paddingBottom: 120 }}>
    {rows}
  </LargeTitleScrollView>
  <TabBar variant="floating" absolute scrollY={scrollY} items={tabs} />
</View>
```

## API reference

### LargeTitleScrollView

`import { LargeTitleScrollView } from "@/components/goodui-native/large-title-header/large-title-header";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `testID` | `string` | – | Used to locate this view in end-to-end tests. > This disables the 'layout-only view removal' optimization for this view! See https://reactnative.dev/docs/view#testid |
| `title` (required) | `string` | – | Screen title. Shown large at the top of the content and small in the bar once collapsed. |
| `variant` | `"transparent" \| "solid"` | `"transparent"` | `transparent` shows the background only once the title collapses; `solid` always shows it. |
| `size` | `"large" \| "medium"` | `"large"` | `largeTitle` (34 pt) or `title1` (28 pt) for denser screens. |
| `labels` | `Partial<LargeTitleHeaderLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `leading` | `ReactNode` | – | Content at the leading edge of the bar, such as a back button. Overrides `onBack`. |
| `actions` | `LargeTitleAction[]` | – | Up to three trailing icon buttons. |
| `onBack` | `() => void` | – | Shows a chevron back button calling this. |
| `backLabel` | `string` | – | Text beside the back chevron. Default "Back". Pass "" for the chevron alone. Same as `labels.back`. |
| `subtitle` | `string` | – | Supporting line under the title, such as "12 unread". |
| `search` | `LargeTitleSearch` | – | A search field under the title. |
| `children` (required) | `ReactNode` | – | Screen content under the title. |
| `scrollY` | `SharedValue<number>` | – | Share the scroll offset, for example with TabBar's hideOnScroll. One is created when omitted. |
| `snap` | `boolean` | `true` | Settle on fully expanded or fully collapsed when a drag ends in between (native). Default `true`. |

### LargeTitleHeader

`import { LargeTitleHeader } from "@/components/goodui-native/large-title-header/large-title-header";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` (required) | `string` | – | Screen title. Shown large at the top of the content and small in the bar once collapsed. |
| `scrollY` (required) | `SharedValue<number>` | – | Vertical scroll offset of the content the header sits on. |
| `size` | `"large" \| "medium"` | `"large"` | `largeTitle` (34 pt) or `title1` (28 pt) for denser screens. |
| `leading` | `ReactNode` | – | Content at the leading edge of the bar, such as a back button. Overrides `onBack`. |
| `onBack` | `() => void` | – | Shows a chevron back button calling this. |
| `backLabel` | `string` | – | Text beside the back chevron. Default "Back". Pass "" for the chevron alone. Same as `labels.back`. |
| `actions` | `LargeTitleAction[]` | `[]` | Up to three trailing icon buttons. |
| `variant` | `"transparent" \| "solid"` | `"transparent"` | `transparent` shows the background only once the title collapses; `solid` always shows it. |
| `collapseDistance` | `SharedValue<number>` | – | Height of the large title block in points, as measured by LargeTitle. Default 52. |
| `labels` | `Partial<LargeTitleHeaderLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

### LargeTitle

`import { LargeTitle } from "@/components/goodui-native/large-title-header/large-title-header";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` (required) | `string` | – | Screen title. Shown large at the top of the content and small in the bar once collapsed. |
| `scrollY` (required) | `SharedValue<number>` | – | Vertical scroll offset of the content the header sits on. |
| `size` | `"large" \| "medium"` | `"large"` | `largeTitle` (34 pt) or `title1` (28 pt) for denser screens. |
| `subtitle` | `string` | – | Supporting line under the title, such as "12 unread". |
| `search` | `LargeTitleSearch` | – | A search field under the title. |
| `collapseDistance` | `SharedValue<number>` | – | Receives the measured height of the title block, so the bar knows when it has collapsed. |
| `onTitleLayout` | `(height: number) => void` | – | Called with the measured height of the title block. |
| `labels` | `Partial<LargeTitleHeaderLabels>` | – | Overrides for the built-in strings (the search field's); a GooduiLocaleProvider pack sets them app-wide. |

## Accessibility

- The large title has accessibilityRole header; the compact copy in the bar is hidden from screen readers so the title is read once.
- The back button and every trailing action are buttons of at least 44 × 44 pt; actions require an accessibilityLabel.
- The search field is labelled by its placeholder; the clear button is labelled 'Clear search'.

## Motion

- Scrolling: the large title fades out between 35 % and 85 % of its height while the compact title fades in and rises 6 pt between 60 % and 100 %.
- The bar background and hairline fade in as the title collapses (the solid variant keeps its background).
- Pulling past the top (iOS bounce) stretches the large title up to 12 % from its leading edge, following the finger.
- When a drag or fling ends with the title half collapsed, the scroll view settles to fully expanded or fully collapsed (native; the web has no drag end events).
- Reduced motion: no stretch, no rise on the compact title, and the settle jumps instead of animating; the cross-fade stays.

## Haptics

- tap on the back button and on trailing actions
- none while scrolling

## Performance

- All scroll-driven styles are computed on the UI thread from one shared scroll offset; scrolling never re-renders React.

## Notes for AI

- Hide the navigator's header for the screen (Stack.Screen options headerShown: false); the component draws its own bar and handles the top inset.
- Use LargeTitleScrollView for ScrollView content. For FlatList or SectionList, put LargeTitle in ListHeaderComponent, render LargeTitleHeader above the list, and share scrollY and collapseDistance.
- Pass at most three actions; each needs key, icon, accessibilityLabel and onPress. The icon receives { color, size }.
- Pass scrollY to share the offset with TabBar hideOnScroll.

## Related

- [Tab bar](https://goodui.dev/native/components/tab-bar.md): A bottom tab bar whose pill stretches toward the next tab and can be dragged to scrub between tabs; the selected icon bounces, badges pop, and it can hide while scrolling.
- [Search bar](https://goodui.dev/native/components/search-bar.md): An iOS-style search field: focusing it shrinks the field while a Cancel button springs in beside it and scope chips cascade in below. Clear button, loading spinner and debounced queries built in.
- [Segmented control](https://goodui.dev/native/components/segmented-control.md): Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.

## Guidance for AI tools

Large title header: An iOS large title that collapses into a compact bar as the content scrolls: the titles cross-fade, the bar fades in, the title stretches when pulled past the top and a half-finished collapse settles on either state. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
