Skip to content

vtex-apps/render-runtime

Repository files navigation

Render Runtime

The Render Runtime app is responsible for handling runtime execution of React apps in the VTEX IO Platform. Additionally, it exports:

ℹ️ Tip: Run vtex setup --typings to add vtex.render-runtime types in your app. This way, IDEs will be able to provide autocomplete for variables and methods.

Check the following sections for more information on the objects exported by the Render Runtime app.

Variables

canUseDOM

A boolean value that indicates whether the code is running in a browser environment (true) or in a Node/SSR environment (false).

ℹ️ Notice that the canUseDOM variable is especially useful in cases the components use DOM related data (e.g: document or window).

Take the following usage example:

import React from 'react'
import { canUseDOM } from 'vtex.render-runtime'

function MyComponent() {
  const data = canUseDOM
    ? window.localStorage.getItem('foo')
    : ''

  return <div>Hello</div>
}

export default MyComponent

Hooks

useRuntime

The useRuntime React hook is useful when creating components since it provides runtime contextual variables and methods.

For an example on its usage, check the following snippet:

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const runtime = useRuntime()

  return <div>Hello</div>
}

Inside the runtime object you can have access to the following variables:

Name Type Description
account string The VTEX account name, (e.g., storecomponents).
binding object An object containing the id and canonicalBaseAddress of the store binding.
culture object An object containing culture, currency and locale information.
deviceInfo object An object specifying the user device type (phone, desktop, tablet, or unknown). This data varies when the user resizes the window.
getSettings function A function that, when called, returns the public settings of an app.
hints object An object which specifies the user device type (phone, desktop, tablet, or unknown) based on the information provided by the CDN. Different from deviceInfo this data is static.
history object A history object reexported from the history package. For further information, check this link.
navigate function A function used in the client-side to define the navigation behaviour.
page string The current page id (e.g., store.home).
pages object Object containing all pages. The keys are the pages ids (e.g., store.home).
route object Object containing data related to the current route, such as id, path, blockId and others.
production boolean Points if the app is in a production workspace (true) or not (false).
query object The URL query string values in a key-value format (e.g., { "foo": "bar" }).
renderMajor number The major version of the Render Runtime app.
rootPath string The store root path (e.g., /ar). If not specified, its value is undefined.
setQuery function A function that can be called to set query string params.
workspace string The current workspace name (e.g., master).

Usage examples

Check the following section for usage examples on how to use the internal runtime variables.

account

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { account } = useRuntime()

  return <div>Welcome to {account}</div>
}

export default MyComponent

binding

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { binding } = useRuntime()

  return <div>Canonical address is "{binding.canonicalBaseAddress}"</div>
}

export default MyComponent

Type:

interface BindingInfo {
  id: string
  canonicalBaseAddress: string
}

Example value:

{
  "id": "aacb06b3-a8fa-4bab-b5bd-2d654d20dcd8",
  "canonicalBaseAddress": "storetheme.vtex.com/"
}

culture

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { culture } = useRuntime()

  return <div>Current active locale is: "{culture.locale}"</div>
}

export default MyComponent

Type:

interface Culture {
  availableLocales: string[]
  country: string
  currency: string
  language: string
  locale: string
  customCurrencyDecimalDigits: number | null
  customCurrencySymbol: string | null
}

Example value:

{
  "availableLocales": [],
  "country": "USA",
  "currency": "USD",
  "language": "en",
  "locale": "en-US",
  "customCurrencyDecimalDigits": null,
  "customCurrencySymbol": "$"
}

deviceInfo

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { deviceInfo } = useRuntime()

  return <div>This page is being rendered on a "{deviceInfo.type}"</div>
}

export default MyComponent

Type:

interface DeviceInfo {
  isMobile: boolean
  type: 'phone' | 'tablet' | 'desktop' | 'unknown'
}

Example value:

{
  "isMobile": false,
  "type": "desktop"
}

getSettings

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { getSettings } = useRuntime()
  const settings = getSettings('vtex.store')

  return <div>This is the store's name: "{settings.storeName}"</div>
}

export default MyComponent

hints

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { hints } = useRuntime()

  if (!hints.desktop) {
    return <div>This is not a desktop</div>
  }

  return <div>This is a desktop</div>
}

export default MyComponent

Type:

interface Hints {
  desktop: boolean
  mobile: boolean
  tablet: boolean
  phone: boolean
  unknown: boolean
}

Example value:

{
  "desktop": true,
  "mobile": false,
  "tablet": false,
  "phone": false,
  "unknown": false,
}

history

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { history } = useRuntime()

  const handleClick = () => {
    history.goBack()
  }

  return <button onClick={handleClick}>Back</button>
}

export default MyComponent

navigate

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { navigate } = useRuntime()

  const handleClick = () => {
    navigate({
      to: '/other-page'
    })
  }

  return <button onClick={handleClick}>Go</button>
}

export default MyComponent

Function param:

interface NavigateOptions {
  fallbackToWindowLocation?: boolean
  hash?: string
  page?: string
  params?: any
  query?: any
  replace?: boolean
  rootPath?: string
  scrollOptions?: false | {
    baseElementId: string,
    behavior: 'auto' | 'smooth'
    left: number
    top: number
  }
  skipSetPath?: boolean
  to?: string
}

page

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { page } = useRuntime()

  return <div>This is the current page id: "{page}"</div>
}

export default MyComponent

pages

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { pages, page } = useRuntime()

  return <div>This is the current page declarer: "{pages[page].declarer}"</div>
}

export default MyComponent

Example value:

{
  "allowConditions": true,
  "context": null,
  "declarer": "vtex.store@2.x",
  "path": "/",
  "routeId": "store.home",
  "blockId": "vtex.store-theme@4.x:store.home",
  "map": []
}

route

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { route } = useRuntime()

  return <div>This is the current route full path: "{route.path}"</div>
}

export default MyComponent

Example value:

{
  "domain": "store",
  "id": "store.home",
  "pageContext": {
    "id": "store.home",
    "type": "route"
  },
  "params": {},
  "path": "/",
  "pathId": "/",
  "queryString": {},
  "breakpointStyles": [
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.common.min.css",
      "mediaQuery": "",
      "type": "common"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.small.min.css",
      "mediaQuery": "screen and (min-width: 20em)",
      "type": "small"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.notsmall.min.css",
      "mediaQuery": "screen and (min-width: 40em)",
      "type": "notsmall"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.large.min.css",
      "mediaQuery": "screen and (min-width: 64em)",
      "type": "large"
    },
    {
      "path": "/_v/public/vtex.styles-graphql/v1/style/vtex.store-theme@4.3.0$style.xlarge.min.css",
      "mediaQuery": "screen and (min-width: 80em)",
      "type": "xlarge"
    }
  ],
  "fonts": "/_v/public/vtex.styles-graphql/v1/fonts/7ead87572b7446c1ca01c45f5065665fc8cfd256",
  "overrides": [
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.product-list@0.28.2$overrides.css",
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.minicart@2.56.0$overrides.css",
    "/_v/public/vtex.styles-graphql/v1/overrides/vtex.store-theme@4.3.0$overrides.css"
  ],
  "rootName": "store.home",
  "ssr": true,
  "styleMeta": {
    "fontsHash": "7ead87572b7446c1ca01c45f5065665fc8cfd256",
    "overridesIds": [
      {
        "id": "vtex.product-list@0.28.2$overrides.css"
      },
      {
        "id": "vtex.minicart@2.56.0$overrides.css"
      },
      {
        "id": "vtex.store-theme@4.3.0$overrides.css"
      }
    ],
    "themeId": "vtex.store-theme@4.3.0$style.min.css"
  },
  "blockId": "vtex.store-theme@4.x:store.home",
  "canonicalPath": "/",
  "metaTags": null,
  "routeId": "store.home",
  "title": null,
  "varyContentById": false
}

production

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { production } = useRuntime()

  if (!production) {
    return <div>This is not a production workspace</div>
  }

  return <div>This is a production workspace</div>
}

export default MyComponent

query

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { query } = useRuntime()

  return <div>The current query strings are {JSON.stringify(query)}</div>
}

export default MyComponent

renderMajor

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { renderMajor } = useRuntime()

  return <div>This page is rendered using vtex.render-runtime@{renderMajor}.x</div>
}

export default MyComponent

rootPath

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { rootPath } = useRuntime()

  if (!rootPath) {
    return <div>The store doesn't have a rootPath set</div>
  }

  return <div>The store rootPath is "{rootPath}"</div>
}

export default MyComponent

setQuery

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { setQuery } = useRuntime()

  const handleClick = () => {
    setQuery({ foo: 'bar' })
  }

  return <button>Set</button>
}

export default MyComponent

workspace

import React from 'react'
import { useRuntime } from 'vtex.render-runtime'

function MyComponent() {
  const { workspace } = useRuntime()

  return <div>This is the {workspace} workspace</div>
}

export default MyComponent

Components

Block (alias ExtensionPoint)

Block is a React component used to create Store Framework blocks.

For implementation details, take the following example.

ℹ️ Notice that the Block component will always expect a specific block id.

import React from 'react'
import { Block } from 'vtex.render-runtime'
// or
// import { ExtensionPoint } from 'vtex.render-runtime'

function MyComponent() {
  return (
    <div>
      Foobar
      <Block id="my-other-block" />
      {/* or <ExtensionPoint id="my-other-block" /> */}
    </div>
  )
}

export default MyComponent

Helmet

Helmet is a component used to add HTML tags inside the <head> tag of a page. Take the following example:

ℹ️ Helmet is a reexport of the Helmet component from the react-helmet library.

import React from 'react'
import { Helmet } from 'vtex.render-runtime'

function MyComponent() {
  return (
    <>
      <Helmet>
        <meta property="og:type" content="article" />
      </Helmet>
    </>
  )
}

export default MyComponent

Link

The Link React component is responsible for rendering an a HTML element that, when clicked, navigates the user to the provided route.

ℹ️ Notice that the Link component has a similar API to the navigate method from the useRuntime hook.

Name Type Description Default
page string The name of the page that the user will be redirected to. Maps to a blocks.json block (e.g., 'store.product')
to string The URL of the page that the user will be redirected to (e.g., /shirt/p?skuId=1). Notice that to is an alternative to page and it contains the whole URL instead of the page name.
params object The param values of the page path in a key-value format (e.g, {slug: 'shirt'}). Params that starts with __ are not considered on path transformations, and can be generaly be used as an alternative to query params {}
query string The representation of the query params that are appended to the page path (e.g., skuId=231.) ''
onClick function A callback that is fired when the user clicks on a component (e.g., () => alert('Salut'))
replace boolean The boolean value used to indicate if it should call (true) the replace function to navigate or not (false)

Other props you pass will be forwarded to the a component and can be used for customization.

Take the following usage examples:

import React from 'react'
import { Link } from 'vtex.render-runtime'

function MyComponent() {
  return <Link to="/otherpage" classname="c-on-base">Hello</Link>
}

export default MyComponent
import React from 'react'
import { Link } from 'vtex.render-runtime'

function MyComponent() {
  const params = {
    slug: PRODUCT_SLUG, // Considered on path transformations (/{slug}/p)
    __listName: 'List of products' // Ignored on path transformations
    __yourProductPageParam: YOUR_PARAM // Ignored on path transformations
  }

  return <Link to="/productpage" params={params}>Hello</Link>
}

export default MyComponent

NoSSR

⚠️ We always recommend using the canUseDOM variable when possible.

NoSSR is a React component that avoids rendering its children during Server-Side Rendering (SSR).

ℹ️ Notice that the NoSSR component is especially useful in cases the components use DOM related data (e.g: document or window).

Take the following usage example:

import React from 'react'
import { NoSSR } from 'vtex.render-runtime'

import DomRelatedComponent from './DomRelatedComponent'

function MyComponent() {
  return (
    <NoSSR onSSR={<div>Loading...</div>}>
      <DomRelatedComponent/>
    </NoSSR>
  )
}

withRuntimeContext (High Order Component)

withRuntimeContext is a React High Order Component (HOC) that allows class components to access the runtime context.

ℹ️ When using function components, you can use useRuntimeContext hook instead.

Take the following usage example:

import React from 'react'
import { withRuntimeContext, RenderContext } from 'vtex.render-runtime'

class MyComponent extends React.Component<{ runtime: RenderContext }>{
  render({ runtime }) {
    return <div>This is the current page id: "{runtime.page}"</div>
  }
}

const MyComponentWithRuntime = withRuntimeContext(MyComponent)

Notice that, when in SSR mode, you can optionally provide the onSSR prop together with a component to render instead.