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

# ais-panel

> Wraps other widgets in a panel for a consistent layout.

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">Vue</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" 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>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/panel/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/api-reference/widgets/panel/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
    </ul>
  </div>
</div>

```vue Signature theme={"system"}
<ais-panel
  // Optional parameters
  :class-names="object"
/>
```

## Import

<Tabs>
  <Tab title="Component">
    To ensure optimal bundle sizes,
    see [Optimize build size](/doc/guides/building-search-ui/going-further/improve-performance/vue#optimize-build-size).

    ```js Vue icon=code theme={"system"}
    import { AisPanel } from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    export default {
      components: {
        AisPanel,
      },
      // ...
    };
    ```
  </Tab>

  <Tab title="Plugin">
    This imports all widgets, even the ones you don't use.
    For more information, see [Get started with Vue InstantSearch](/doc/guides/building-search-ui/getting-started/vue).

    ```js JavaScript icon="code" theme={"system"}
    import Vue from "vue";
    import InstantSearch from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    Vue.use(InstantSearch);
    ```
  </Tab>
</Tabs>

<Card title="See this widget in action" icon="monitor-play" href="https://instantsearchjs.netlify.app/stories/vue/?selectedKind=ais-panel" horizontal>
  Preview this widget and its behavior.
</Card>

## About this widget

The `ais-panel` widget wraps other widgets in a consistent panel design.
It also reacts by adding a CSS class when the widget no longer can refine.
An example is when a [`ais-refinement-list`](/doc/api-reference/widgets/refinement-list/vue)
becomes empty because of the current search results.

## Examples

```vue Vue icon=code theme={"system"}
<ais-panel>
  <p>Panel content</p>
</ais-panel>
```

## Props

<ParamField body="class-names" type="object" default="{}">
  The [CSS classes you can override](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue#style-your-widgets):

  * `ais-Panel`. The root of the widget.
  * `ais-Panel--noRefinement`. The root of the widget without refinement.
  * `ais-Panel-header`. The header of the widget.
  * `ais-Panel-body`. The content of the widget.
  * `ais-Panel-footer`. The footer of the widget.

  ```vue Vue icon=code theme={"system"}
  <ais-panel
    :class-names="{
      'ais-Panel': 'MyCustomPanel',
      'ais-Panel-body': 'MyCustomPanelBody',
      // ...
    }"
  >
    <p>Panel content</p>
  </ais-panel>
  ```
</ParamField>

## Customize the UI

<ParamField body="default">
  The slot to provide a body to the widget.

  Note that when you implement this slot, none of the other slots will change the output, as the default slot surrounds them.

  **Scope**

  * `hasRefinements: boolean`. Whether the inner widget can refine, will be `false` if it has no possible refinements.

  ```vue Vue icon=code theme={"system"}
  <ais-panel>
    <template v-slot:default="{ hasRefinements }">
      <p v-if="!hasRefinements">no results</p>
      <ais-refinement-list attribute="brand" />
    </template>
  </ais-panel>
  ```
</ParamField>

<ParamField body="header">
  The slot to provide a header to the widget.

  **Scope**

  * `hasRefinements: boolean`. Whether the inner widget can refine, will be `false` if it has no possible refinements.

  ```vue Vue icon=code theme={"system"}
  <ais-panel>
    <template v-slot:header="{ hasRefinements }">
      <p>
        Brand <span v-if="!hasRefinements">(no results)</span>
      </p>
    </template>
    <template v-slot:default>
      <ais-refinement-list attribute="brand" />
    </template>
  </ais-panel>
  ```
</ParamField>

<ParamField body="footer">
  The slot to provide a footer to the widget.

  **Scope**

  * `hasRefinements: boolean`. Whether the inner widget can refine, will be `false` if it has no possible refinements.

  ```vue Vue icon=code theme={"system"}
  <ais-panel>
    <template v-slot:default>
      <ais-refinement-list attribute="brand" />
    </template>
    <template v-slot:footer="{ hasRefinements }">
      <p v-if="!hasRefinements">no results</p>
    </template>
  </ais-panel>
  ```
</ParamField>

## HTML output

```html HTML icon=code-xml theme={"system"}
<div class="ais-Panel">
  <div class="ais-Panel-header">Header</div>
  <div class="ais-Panel-body">Panel content</div>
  <div class="ais-Panel-footer">Footer</div>
</div>
```
