Skip to content

Commit

Permalink
Add startViewTransition support (#7648)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Oct 12, 2023
1 parent 7eeaa77 commit 5f175cd
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 67 deletions.
42 changes: 42 additions & 0 deletions .changeset/start-view-transition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
"@remix-run/react": minor
---

Add support for the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) via `document.startViewTransition` to enable CSS animated transitions on SPA navigations in your application.

The simplest approach to enabling a View Transition in your Remix app is via the new `<Link unstable_viewTransition>` prop. This will cause the navigation DOM update to be wrapped in `document.startViewTransition` which will enable transitions for the DOM update. Without any additional CSS styles, you'll get a basic cross-fade animation for your page.

If you need to apply more fine-grained styles for your animations, you can leverage the `unstable_useViewTransitionState` hook which will tell you when a transition is in progress and you can use that to apply classes or styles:

```jsx
function ImageLink(to, src, alt) {
let isTransitioning = unstable_useViewTransitionState(to);
return (
<Link to={to} unstable_viewTransition>
<img
src={src}
alt={alt}
style={{
viewTransitionName: isTransitioning ? "image-expand" : "",
}}
/>
</Link>
);
}
```

You can also use the `<NavLink unstable_viewTransition>` shorthand which will manage the hook usage for you and automatically add a `transitioning` class to the `<a>` during the transition:

```css
a.transitioning img {
view-transition-name: "image-expand";
}
```

```jsx
<NavLink to={to} unstable_viewTransition>
<img src={src} alt={alt} />
</NavLink>
```

For more information on using the View Transitions API, please refer to the [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/) guide from the Google Chrome team.
10 changes: 10 additions & 0 deletions docs/components/form.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ If true, it will submit the form with the browser instead of client side routing

This is recommended over [`<form>`][form_element]. When the `action` prop is omitted, `<Form>` and `<form>` will sometimes call different actions depending on what the current URL is since `<form>` uses the current URL as the default, but `<Form>` uses the URL for the route the form is rendered in.

## `unstable_viewTransition`

The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state].

<docs-warn>
Please note that this API is marked unstable and may be subject to breaking changes without a major release.
</docs-warn>

## Notes

### `?index`
Expand Down Expand Up @@ -127,3 +135,5 @@ See also:
[form_vs_fetcher]: ../discussion/form-vs-fetcher
[fetcher_form]: ../hooks/use-fetcher#fetcherform
[progressive_enhancement]: ../discussion/progressive-enhancement
[use-view-transition-state]: ../hooks//use-view-transition-state
[view-transitions]: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
47 changes: 47 additions & 0 deletions docs/components/link.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,52 @@ function SomeComp() {

This state is inaccessible on the server as it is implemented on top of [`history.state`][history_state].

## `unstable_viewTransition`

The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`:

```jsx
<Link to={to} unstable_viewTransition>
Click me
</Link>
```

If you need to apply specific styles for this view transition, you will also need to leverage the [`unstable_useViewTransitionState()`][use-view-transition-state]:

```jsx
function ImageLink(to) {
const isTransitioning =
unstable_useViewTransitionState(to);
return (
<Link to={to} unstable_viewTransition>
<p
style={{
viewTransitionName: isTransitioning
? "image-title"
: "",
}}
>
Image Number {idx}
</p>
<img
src={src}
alt={`Img ${idx}`}
style={{
viewTransitionName: isTransitioning
? "image-expand"
: "",
}}
/>
</Link>
);
}
```

<docs-warn>
Please note that this API is marked unstable and may be subject to breaking changes without a major release.
</docs-warn>

[scroll_restoration_component]: ./scroll-restoration
[history_state]: https://developer.mozilla.org/en-US/docs/Web/API/History/state
[use-view-transition-state]: ../hooks//use-view-transition-state
[view-transitions]: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
83 changes: 83 additions & 0 deletions docs/components/nav-link.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ a.active {

When a `NavLink` is active it will automatically apply `<a aria-current="page">` to the underlying anchor tag. See [aria_current][aria_current] on MDN.

### `.pending`

A `pending` class is added to a `<NavLink>` component when it is pending during a navigation, so you can use CSS to style it.

```tsx
<NavLink to="/messages" />
```

```css
a.pending {
color: red;
}
```

### `.transitioning`

A `transitioning` class is added to a `<NavLink unstable_viewTransition>` component when it is transitioning during a navigation, so you can use CSS to style it.

```tsx
<NavLink to="/messages" unstable_viewTransition />
```

```css
a.transitioning {
view-transition-name: my-transition;
}
```

## Props

### `className` callback
Expand Down Expand Up @@ -108,9 +136,64 @@ Adding the `caseSensitive` prop changes the matching logic to make it case-sensi
| `<NavLink to="/SpOnGe-bOB" />` | `/sponge-bob` | true |
| `<NavLink to="/SpOnGe-bOB" caseSensitive />` | `/sponge-bob` | false |

## `unstable_viewTransition`

The `unstable_viewTransition` prop enables a [View Transition][view-transitions] for this navigation by wrapping the final state update in `document.startViewTransition()`. By default, during the transition a `transitioning` class will be added to the `<a>` element that you can use to customize the view transition.

```css
a.transitioning p {
view-transition-name: "image-title";
}

a.transitioning img {
view-transition-name: "image-expand";
}
```

```jsx
<NavLink to={to} unstable_viewTransition>
<p>Image Number {idx}</p>
<img src={src} alt={`Img ${idx}`} />
</NavLink>
```

You may also use the `className`/`style` props or the render props passed to `children` to further customize based on the `isTransitioning` value.

```jsx
<NavLink to={to} unstable_viewTransition>
{({ isTransitioning }) => (
<>
<p
style={{
viewTransitionName: isTransitioning
? "image-title"
: "",
}}
>
Image Number {idx}
</p>
<img
src={src}
alt={`Img ${idx}`}
style={{
viewTransitionName: isTransitioning
? "image-expand"
: "",
}}
/>
</>
)}
</NavLink>
```

<docs-warn>
Please note that this API is marked unstable and may be subject to breaking changes without a major release.
</docs-warn>

### `<Link>` props

All other props of [`<Link>`][link_component] are supported.

[link_component]: ./link
[aria_current]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current
[view-transitions]: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
31 changes: 31 additions & 0 deletions docs/hooks/use-view-transition-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: unstable_useViewTransitionState
toc: false
---

# `unstable_useViewTransitionState`

This hook returns `true` when there is an active [View Transition][view-transitions] to the specified location. This can be used to apply finer-grained styles to elements to further customize the view transition. This requires that view transitions have been enabled for the given navigation via the [unstable_viewTransition][link-view-transition] prop on the `Link` (or the `Form`, `navigate`, or `submit` call).

Consider clicking on an image in a list that you need to expand into the hero image on the destination page:

```jsx
function NavImage({ src, alt, id }) {
let to = `/images/${idx}`;
let vt = unstable_useViewTransitionState(href);
return (
<Link to={to} unstable_viewTransition>
<img
src={src}
alt={alt}
style={{
viewTransitionName: vt ? "image-expand" : "",
}}
/>
</Link>
);
}
```

[link-view-transition]: ../components/link#unstable_viewtransition
[view-transitions]: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
1 change: 1 addition & 0 deletions packages/remix-react/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export {
useSubmit,
unstable_useBlocker,
unstable_usePrompt,
unstable_useViewTransitionState,
} from "react-router-dom";

export type {
Expand Down
4 changes: 2 additions & 2 deletions packages/remix-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"typings": "dist/index.d.ts",
"module": "dist/esm/index.js",
"dependencies": {
"@remix-run/router": "1.9.0",
"@remix-run/router": "1.10.0-pre.0",
"@remix-run/server-runtime": "2.0.1",
"react-router-dom": "6.16.0"
"react-router-dom": "6.17.0-pre.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.17.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/remix-server-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"typings": "dist/index.d.ts",
"module": "dist/esm/index.js",
"dependencies": {
"@remix-run/router": "1.9.0",
"@remix-run/router": "1.10.0-pre.0",
"@types/cookie": "^0.4.1",
"@web3-storage/multipart-parser": "^1.0.0",
"cookie": "^0.4.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/remix-testing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"dependencies": {
"@remix-run/node": "2.0.1",
"@remix-run/react": "2.0.1",
"@remix-run/router": "1.9.0",
"react-router-dom": "6.16.0"
"@remix-run/router": "1.10.0-pre.0",
"react-router-dom": "6.17.0-pre.0"
},
"devDependencies": {
"@types/node": "^18.17.1",
Expand Down

0 comments on commit 5f175cd

Please sign in to comment.