> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# renderState

> Object with state data about all widgets.

export const FlavorSwitcher = ({current, baseHref = "", options = [], label = "InstantSearch framework"}) => {
  if (options.length === 0) {
    return <div className="not-prose" role="alert" style={{
      margin: "0.25rem 0 1.5rem",
      padding: "0.75rem",
      border: "1px solid #f59e0b",
      borderRadius: "0.625rem",
      color: "inherit",
      fontSize: "0.875rem"
    }}>
        FlavorSwitcher requires at least one option.
      </div>;
  }
  const selected = options.find(option => option.value === current) ?? options[0];
  return <div className="not-prose mint-flavor-switcher">
      <style>{`
        .mint-flavor-switcher {
          --mfs-bg: #ffffff;
          --mfs-bg-hover: #f4f4f5;
          --mfs-bg-current: #eef2ff;
          --mfs-border: #d4d4d8;
          --mfs-fg: #18181b;
          --mfs-muted: #71717a;
          --mfs-accent: #4f46e5;
          position: relative;
          width: min(100%, 19rem);
          margin: 0.25rem 0 1.5rem;
          color: var(--mfs-fg);
          font-size: 0.875rem;
          line-height: 1.25rem;
        }

        .dark .mint-flavor-switcher {
          --mfs-bg: #18181b;
          --mfs-bg-hover: #27272a;
          --mfs-bg-current: #272747;
          --mfs-border: #3f3f46;
          --mfs-fg: #fafafa;
          --mfs-muted: #a1a1aa;
          --mfs-accent: #a5b4fc;
        }

        .mint-flavor-switcher details {
          position: relative;
        }

        .mint-flavor-switcher summary {
          display: flex;
          min-height: 2.75rem;
          box-sizing: border-box;
          align-items: center;
          justify-content: space-between;
          gap: 0.75rem;
          padding: 0.625rem 0.75rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          color: var(--mfs-fg);
          cursor: pointer;
          font-weight: 600;
          list-style: none;
          transition: border-color 150ms ease, box-shadow 150ms ease;
        }

        .mint-flavor-switcher summary::-webkit-details-marker {
          display: none;
        }

        .mint-flavor-switcher summary:hover {
          border-color: var(--mfs-accent);
        }

        .mint-flavor-switcher summary:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: 2px;
        }

        .mint-flavor-switcher__label {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        .mint-flavor-switcher__chevron {
          flex: none;
          transition: transform 150ms ease;
        }

        .mint-flavor-switcher details[open] .mint-flavor-switcher__chevron {
          transform: rotate(180deg);
        }

        .mint-flavor-switcher__menu {
          position: absolute;
          z-index: 50;
          top: calc(100% + 0.375rem);
          left: 0;
          width: 100%;
          box-sizing: border-box;
          margin: 0;
          padding: 0.375rem;
          border: 1px solid var(--mfs-border);
          border-radius: 0.625rem;
          background: var(--mfs-bg);
          box-shadow: 0 12px 30px rgb(0 0 0 / 16%);
          list-style: none;
        }

        .mint-flavor-switcher__menu li {
          margin: 0;
          padding: 0;
        }

        .mint-flavor-switcher__option {
          display: grid;
          gap: 0.125rem;
          padding: 0.625rem 0.75rem;
          border-radius: 0.4rem;
          color: var(--mfs-fg);
          text-decoration: none;
        }

        .mint-flavor-switcher__option:hover {
          background: var(--mfs-bg-hover);
        }

        .mint-flavor-switcher__option:focus-visible {
          outline: 2px solid var(--mfs-accent);
          outline-offset: -2px;
        }

        .mint-flavor-switcher__option[aria-current="page"] {
          background: var(--mfs-bg-current);
          color: var(--mfs-accent);
        }

        .mint-flavor-switcher__name {
          font-weight: 600;
        }

        .mint-flavor-switcher__description {
          color: var(--mfs-muted);
          font-size: 0.8125rem;
        }

        @media (prefers-reduced-motion: reduce) {
          .mint-flavor-switcher summary,
          .mint-flavor-switcher__chevron {
            transition: none;
          }
        }
      `}</style>

      <details>
        <summary aria-label={`${label}: ${selected.label}`}>
          <span className="mint-flavor-switcher__label">{selected.label}</span>
          <svg className="mint-flavor-switcher__chevron" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="m6 9 6 6 6-6" />
          </svg>
        </summary>

        <ul className="mint-flavor-switcher__menu" aria-label={label}>
          {options.map(option => {
    const isCurrent = option.value === selected.value;
    const href = option.href ?? `${baseHref.replace(/\/$/, "")}/${encodeURIComponent(option.value)}`;
    return <li key={option.value}>
                <a className="mint-flavor-switcher__option" href={href} aria-current={isCurrent ? "page" : undefined}>
                  <span className="mint-flavor-switcher__name">
                    {option.label}
                  </span>
                  {option.description ? <span className="mint-flavor-switcher__description">
                      {option.description}
                    </span> : null}
                </a>
              </li>;
  })}
        </ul>
      </details>
    </div>;
};

<div className="mint-flavor-switcher-slot not-prose">
  <FlavorSwitcher
    current="js"
    baseHref="/doc/api-reference/widgets/render-state"
    options={[
{ value: "js", label: "JavaScript", description: "InstantSearch.js" },
{ value: "react", label: "React", description: "React InstantSearch" },
]}
  />
</div>

```ts Signature theme={"system"}
search.renderState: object;
```

## About this widget

The `renderState` property provides all the data and functions from the widgets.
It lets you access the render state of any widget from anywhere,
so you can create custom widgets or refine the search outside the InstantSearch.js lifecycle.

<Note>
  The `renderState` property is available starting in InstantSearch.js v4.9.
</Note>

## Examples

You can access the render state of the `searchBox` widget.

```js JavaScript icon=code theme={"system"}
const indexName = "<index-name>";
const search = instantsearch({
  indexName,
  // ...
});
search.addWidgets([
  searchBox({
    container: "<your-container>",
  }),
]);
search.start();

console.log(search.renderState[indexName].searchBox);
/*
  {
    query: string;
    refine: Function;
    clear: Function;
    isSearchStalled: boolean;
    widgetParams: object;
  }
*/
```

## Working with virtual widgets

To access the `renderState` of widgets, you must add them to the InstantSearch instance.
If you don't want to add a widget to the UI,
but want to get access to its `renderState`, you can add it as a virtual, or renderless widget.

<CodeGroup>
  ```html HTML theme={"system"}
  <button id="next-page-button">Next Page</button>
  ```

  ```js JavaScript theme={"system"}
  const renderer = () => null;
  const virtualPagination = connectPagination(renderer);

  search.addWidgets([virtualPagination()]);

  // Add a click listener to the button
  document.querySelector("#next-page-button").addEventListener("click", () => {
    // Get the `renderState` of the `pagination` widget
    const paginationRenderState = search.renderState[indexName].pagination;

    // Get the current page
    const currentPage = paginationRenderState.currentRefinement;

    // Call `refine` to move to the next page
    paginationRenderState.refine(currentPage + 1);
  });
  ```
</CodeGroup>

## Type definition

```ts TypeScript icon=code theme={"system"}
type RenderState = {
  [indexId: string]: IndexRenderState;
}

type IndexRenderState = Partial<{
  searchBox: SearchBoxState;
  autocomplete: AutocompleteState;
  breadcrumb: BreadcrumbState;
  clearRefinements: ClearRefinementsState;
  configure: ConfigureState;
  currentRefinements: CurrentRefinementsState;
  hierarchicalMenu: {
    [attribute: string]: HierarchicalMenuState;
  }
  hits: HitsState;
  infiniteHits: InfiniteHitsState;
  analytics: AnalyticsState;
  places: PlacesState;
  poweredBy: PoweredByState;
  range: {
    [attribute: string]: RangeState;
  ratingMenu: {
    [attribute: string]: RatingMenuState;
  };
  numericMenu: {
    [attribute: string]: NumericMenuState;
  };
  voiceSearch: VoiceSearchState;
  geoSearch: GeoSearchState;
  queryRules: QueryRulesState;
  hitsPerPage: HitsPerPageState;
  pagination: PaginationState;
  refinementList: {
    [attribute: string]: RefinementListState;
  };
  answers: AnswersState;
}>;
```
