@curi/react-dom

Installation

The package can be installed through npm (you need to have Node & NPM installed).

npm install @curi/react-dom

Prefer inline scripts? A full (.umd.js) and minified (.min.js) script is available for every version through Unpkg. You can access the package's exports through window.CuriReactDOM.

About

The @curi/react-dom package provides a number of React components that you can use for rendering your application.

For more information on using Curi with React DOM, please check out the React DOM guide.

API

curiProvider()

The application needs a component at its root to re-render the application when new responses are emitted and to make routing related available through React's context. This component is created by passing the Curi router to the curiProvider() function.

Note:

Why does @curi/react-dom export a function to create a component and not just a component? Props signify values that can change, but an application should only ever have one router. By hard-coding the router into a component, we avoid having to handle the possibility of switching routers (which should not happen).

Note: All of the other components provided by @curi/react-dom must be descendants of the component created by curiProvider().
import { curiProvider } from '@curi/react-dom';

const router = curi(history, routes);
const Router = curiProvider(router);

const App = () => (
  <Router>
    {({ response, navigation, router }) => {
      const { body:Body } = response;
      return <Body response={response} />;
    }}
  </Router>
);

Arguments

router

A Curi router.

import { curiProvider } from "@curi/react-dom";

const router = curi(history, routes);
const Router = curiProvider(router);

Props

children

children is a render-invoked function. When it is called, it will be passed an object with three properties:

propertydescription
responsethe response object generated for the current location
navigationthe action of the navigation and the previous response object
routerthe Curi router

<Focus>

<Focus> lets you focus a DOM element whenever there is a new response.

The DOM component that gets the ref should either already be "focusable", like an <input>, or be given a tabIndex prop (usually with the value of -1). If neither of these conditions is met, then the document's <body> will be focused.

The focused element will have an outline (the exact style varies by browser). You can remove this visual with a CSS outline of "none".

Note: Only one <Focus> should be rendered at a time.
import { Focus } from "@curi/react-dom";

<Focus>
  {ref => (
    <div tabIndex={-1} ref={ref}>
      {/* ... */}
    </div>
  )}
</Focus>

Props

children()

The children() function is a render-invoked prop that will be passed a ref. The ref should be attached to the element that you want focused.

If you need to pass this through class/functional components, you should use either React.forwardRef() or pass it as a prop with a name other than ref (like innerRef).

<Focus>
  {ref => (
    <div tabIndex={-1} ref={ref} />
  )}
</Focus>

<Focus>
  {ref => <SomeComponent innerRef={ref} />}
</Focus>

preventScroll

The default behavior for focusing an element is to scroll to it. If you want to prevent this, pass preventScroll={true} to the <Focus>.

// scrolls
<Focus>{ref => ...}</Focus>

// does not scroll
<Focus preventScroll={true}>{ref => ...}</Focus>

preserve

The default focus behavior is to always focus the element that the ref is attached to. However, if you want to preserve the focus on some other element (e.g. an autofocused element), preserve={true} will stop the ref element from claiming the focus.

This only works when the already-focused element is a child of the ref element. If it is not a child, then the ref element will take the focus.

// claim focus for the <div>
<Focus>
  {ref => (
    <div tabIndex={-1} ref={ref}>
      <input autoFocus={true} />
    </div>
  )}
</Focus>

// preserve focus on the <input>
<Focus preserve={true}>
  {ref => (
    <div tabIndex={-1} ref={ref}>
      <input autoFocus={true} />
    </div>
  )}
</Focus>

<Curious>

A context consumer component for injecting router values into components.

import { Curious } from '@curi/react-dom';

const MyComponent = () => (
  <Curious>
    {({ router, response, navigation }) => {
      // pass these props to any components
      // that needs them
      return (
        <ThingThatNeedsResponse
          response={response}
        />
      );
    }}
  </Curious>
);

Props

children

A render-invoked function that returns a React element. This function will receive an object with router, response and navigation properties.

<Active>

The <Active> component is used to render based on whether or not a route is "active" (its name and params match the current response's name and params) using a render-invoked children function.

import { Active } from '@curi/react-dom';

const ActiveLink = ({
  name,
  params,
  partial,
  forward,
  ...rest
}) => (
  <Active name={name} params={params} partial={partial}>
    {active => (
      <Link
        name={name}
        params={params}
        {...rest}
        forward={{
          ...forward,
          className: [forward.className || "", active ? "active" : ""].join(" ")
        }}
      >
        {children}
      </Link>
    )}
  </Active>
);

<ActiveLink name="Home">Home</ActiveLink>
Note:

This relies on the active route interaction from @curi/route-active being added to your router.

import active from '@curi/route-active';

const router = curi(history, routes, {
  route: [active()]
});

Props

name

The name of the route to compare against the response object.

params

An object containing route parameters. These will be compared against the route params of the response object.

children

A render-invoked function whose first argument is whether the route (determined using the name and params) is active.

// response = { name: "Photo", params: { id: "abcde" }}

<Active name="Photo" params={{ id: "abcde" }}>
  {active => ( // if active === true
    <Photo className={active ? "active" : "inactive"} />
  )}
</Active>
// <Photo className="active" />

<Active name="Photo" params={{ id: "qwerty" }}>
  {active => ( // if active === false
    <Photo className={active ? "active" : "inactive"} />
  )}
</Active>
// <Photo className="inactive" />

The second argument passed to the render-invoked function is the current response. <Active> only checks if the route is active (i.e. matches the current location's pathname). If you want to check if a query or hash match the current location, you should do this yourself inside of the render-invoked function. You can compare the query/hash against the response's location.

<Active name="Home">
  {(active, response) => {
    const activeHash = response.hash === "ahoy"
    // ...
  }}
</Active>

partial

When true, partial allows ancestor routes to be considered active. Defaults to false.

// response = { name: "Photo", params: { id: "abcde" }}
// where "Photo" is a child route of "Album"

<Active name="Album">
  {active => ( // if active === false
    <Album className={active ? "active" : "inactive"} />
  )}
</Active>
// <Album className="inactive" />

<Active name="Album" partial={true}>
  {active => ( // if active === true
    <Album className={active ? "active" : "inactive"} />
  )}
</Active>
// <Album className="active" />

<Block>

The <Block> component lets you prevent navigation until a user has confirmed that they want to navigate. This can be useful when the user attempts to navigate away from a partially filled form. This will not prevent the user from navigating to another site, it only works for navigation within the application.

import { Block } from '@curi/react-dom';

Props

active

A boolean, which is true by default. When it is true, the navigation block is active. When it is false, navigation will not be blocked.

// will block navigation
<Block active={true} confirm={confirm} />

// will not block navigation
<Block active={false} confirm={confirm} />

confirm

The confirm prop is a function that will be called whenever there is navigation.

argumentdescription
locationthe location that is being navigated to
actionthe type of navigation
successa function to call when navigation should happen
failurea function to call when navigation should be cancelled.
<Block
  confirm={({ location, action }, success, failure) => {
    const response = window.confirm("Shall we?");
    if (response) {
      success();
    } else {
      failure();
    }
  }}
/>