Flow

Steve Ruiz

@steveruizok

Experiment with stacked navigation flow, kind of like Framer Classic’s FlowController. Much refactored.

🍕Download this example project!

🧶 And click here for a user-selectable version of this readme.

…and ignore that other version on the Store!

Changelog

27/6 Rewrites how pages are shown. In previous versions the component would unmount components that don’t need to be shown, keeping track of only the current and previous page. In this version, all pages in the stack are kept until removed from the stack.

For example, if we navigate to PageA, PageB, and then PageC, all three pages will remain mounted. If we show previous, our position will move to PageB but PageC will remain mounted. If we then navigate from PageB to PageA, PageC will be unmounted and we’ll mount a second (but separate) PageA.

This is useful for cases where pages have content (such as form fields, scroll positions, or interaction states) that need to be maintained. Traveling “back” to a previously visited screen will restore that screen exactly as the user had left it.

This is also useful for navigation flows that load different versions of the same page, such as articles with different content but the same “page”. (More on this in future updates).

Tips

A link’s target can either be the name of a Frame (so long as it’s connected to the Flow component) or the name of a Marker that you’ve added to one of your connected Frames.

You can navigate from code, too. Click here to see a basic code component that will work with the Flow package.

You can navigate from Overrides, too.

import { Override } from “framer"
// @ts-ignore
import { showNext, showPrevious } from "@framer/steveruizok.flow/code"

export function Button(): Override {
    return {
        onTap: () => showNext(“screen_a”)
    }
}

export function BackButton(): Override {
    return {
        onTap: () => showPrevious()
    }
}

onChangePage

You can override the onChangePage event to get the name of the current page.

import { Override } from “framer”

export function ChangePage(): Override {
    return {
        onChangePage: (name, position, stack) => {
            console.log(name, position, stack)
        }
    }
}

Transitions

If you want to tweak the component’s transitions, override the variants prop. It takes three variants: behind, current, and ahead.

import { Override } from “framer"

export function VerticalPush(): Override {
    return {
        unmountHidden: true,
        variants: {
            behind: {
                y: "-100%"
            },
            current: {
                y: “0%”
            },
            ahead: {
                y: “100%”
            },
        },
    }
}

When moving “up” the stack, the new Frame will start at ahead and move to current, while the previous Frame moves from current to behind. When moving “down” the stack, the current Frame will move from behind to current, while the previous Frame will move from current to above.

An “instant” set of transitions would look like this:

import { Override } from “framer”

export function Instant(): Override {
    return {
        variants: {
            behind: {},
            current: {},
            ahead: {},
        },
    }
}

See the defaultProps at the bottom of this page for the default animation variants.

Unmount Hidden

By default, the component will preserve all of the Frames in the stack. They’ll stay mounted, so you won’t lose any data state or scroll positions. However, you might also want to just instantly snap between pages, unmounting all but the currently shown page. (You’d probably want to use the “instant” transitions, too).

import { Override } from “framer”

export function InstantUnmount(): Override {
    return {
        unmountHidden: true,
        variants: {
            behind: {},
            current: {},
            ahead: {},
        },
    }
}

Swiping

import { Override } from “framer"
// @ts-ignore
import { showPrevious } from "@framer/steveruizok.flow/code”

export function Instant(): Override {
    return {
        onSwipeRight: showPrevious()
    }
}

defaultProps

Here are all of the component’s default props.

export function Instant(): Override {
    return {
        unmountHidden: false,
        stackPosition: 0,
        current: 0,
        pages: [],
        swipe: true,
        swipeDistance: 32,
        onSwipeLeft: () => null,
        onSwipeRight: () => null,
        onSwipeUp: () => null,
        onSwipeDown: () => null,
        onChangePage: (name, position, stack) => null,
        background: "none",
        variants: {
            behind: {
                x: "0%",
                filter: "brightness(50%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.36,
                },
            },
            current: {
                x: "0%",
                filter: "brightness(100%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.36,
                },
            },
            ahead: {
                x: "100%",
                filter: "brightness(100%)",
                transition: {
                    ease: [0.23, -0.04, 0.31, 1.01],
                    duration: 0.28,
                },
            },
        },
    }
}
By using our website, you agree to the use of cookies as described in our  Privacy Policy —
I Agree