---
title: "Theming: Distributing Shared Themes & Parts"
framework: vue
version: "36.1.0"
---

# Theming: Distributing Shared Themes & Parts

For organisations with multiple applications, you can create your own themes and parts to share styles between applications.

### Creating Themes From Scratch

Most applications create themes by starting with a built-in theme like `themeQuartz` and using the `withParams` and `withPart` methods to generate a customised version.

The `createTheme` function creates a new theme containing core styles but no parts. If you're going to change most of the parts anyway, starting from a new theme will reduce the bundle size compared to starting with a built-in theme.

```js
import { createTheme, iconSetMaterial, colorSchemeVariable } from 'ag-grid-community';

const myCustomTheme = createTheme()
    // add just the parts you want
    .withPart(iconSetMaterial)
    .withPart(colorSchemeVariable)
    // set default param values
    .withParams({
        accentColor: 'red',
        iconSize: 18,
    });
```

Note that the checkboxes in the example below are using the default styles from your web browser, because the parts containing their styles have not been added. This is useful if your application does not contain these features, or if you want a clean base upon which to apply your own checkbox styles.

#### Creating a Theme From Scratch

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AllCommunityModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  RowSelectionOptions,
  Theme,
  colorSchemeVariable,
  createTheme,
  enableDevValidations,
  iconSetMaterial,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([AllCommunityModule]);

const myCustomTheme = createTheme()
  // add just the parts you want
  .withPart(iconSetMaterial)
  .withPart(colorSchemeVariable)
  // set default param values
  .withParams({
    accentColor: "red",
    iconSize: 18,
  });

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :rowData="rowData"
      :theme="theme"
      :defaultColDef="defaultColDef"
      :rowSelection="rowSelection"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "make" },
      { field: "model" },
      { field: "price" },
    ]);
    const rowData = ref<IOlympicData[] | null>(
      (() => {
        const rowData: any[] = [];
        for (let i = 0; i < 10; i++) {
          rowData.push({
            make: "Toyota",
            model: "Celica",
            price: 35000 + i * 1000,
          });
          rowData.push({
            make: "Ford",
            model: "Mondeo",
            price: 32000 + i * 1000,
          });
          rowData.push({
            make: "Porsche",
            model: "Boxster",
            price: 72000 + i * 1000,
          });
        }
        return rowData;
      })(),
    );
    const theme = ref<Theme | "legacy">(myCustomTheme);
    const defaultColDef = ref<ColDef>({
      editable: true,
      flex: 1,
      minWidth: 100,
      filter: true,
    });
    const rowSelection = ref<RowSelectionOptions | "single" | "multiple">({
      mode: "multiRow",
      checkboxes: true,
    });

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      rowData,
      theme,
      defaultColDef,
      rowSelection,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Creating a Theme From Scratch](https://www.ag-grid.com/examples/theming-distribution/creating-themes/vue3)

### Creating Your Own Parts

For organisations that create a library of reusable styles and share them among many applications, parts can be a convenient way to package up styles and parameters so that each application can use a subset of the whole library.

The benefit of using parts rather than adding CSS in your application stylesheets is that the CSS is scoped: the CSS you provide will only apply to grids with your theme applied, whereas by default CSS in your application stylesheets will apply to all grids unless you add rules to prevent it.

The `createPart` function creates a new part. It takes an options object with the following properties:

```js
import { createPart } from 'ag-grid-community';

const myCheckboxStyle = createPart({
    // By setting the feature, adding this part to a theme will remove the
    // theme's existing checkboxStyle, if any
    feature: 'checkboxStyle',
    params: {
        // Declare parameters added by the custom CSS and provide default values
        checkboxCheckedGlowColor: { ref: 'accentColor' },
        checkboxGlowColor: { ref: 'foregroundColor', mix: 0.5 },
        // If you want to provide new default values for parameters already defined
        // by the grid, you can do so too
        accentColor: 'red',
    },
    // Add some CSS to this part.
    // If your application is bundled with Vite you can put this in a separate
    // file and import it with `import checkboxCSS from "./checkbox.css?inline"`
    css: `
        .ag-checkbox-input-wrapper {
            border-radius: 4px;
            /* Here we're referencing the checkboxGlowColor parameter in CSS, we need
               to add the --ag- prefix and use kebab-case */
            box-shadow: 0 0 5px 4px var(--ag-checkbox-glow-color);

        ... css implementing the new checkbox style ...

        `,
});
```

#### Creating Parts

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  GridState,
  ModuleRegistry,
  RowSelectionOptions,
  Theme,
  createPart,
  enableDevValidations,
  themeQuartz,
} from "ag-grid-community";
import { AllEnterpriseModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([AllEnterpriseModule]);

const myCheckboxStyle = createPart({
  // By setting the feature, adding this part to a theme will remove the
  // theme's existing checkboxStyle, if any
  feature: "checkboxStyle",
  params: {
    // Declare parameters added by the custom CSS and provide default values
    checkboxCheckedGlowColor: { ref: "accentColor" },
    checkboxGlowColor: { ref: "foregroundColor", mix: 0.5 },
    // If you want to provide new default values for parameters already defined
    // by the grid, you can do so too
    accentColor: "red",
  },
  // Add some CSS to this part.
  // If your application is bundled with Vite you can put this in a separate
  // file and import it with `import checkboxCSS "./checkbox.css?inline"`
  css: `
        .ag-checkbox-input-wrapper {
            border-radius: 4px;
            /* Here we're referencing the checkboxGlowColor parameter in CSS, we need
               to add the --ag- prefix and use kebab-case */
            box-shadow: 0 0 5px 4px var(--ag-checkbox-glow-color);
            width: 16px;
            height: 16px;
        
            &.ag-checked {
                box-shadow: 0 0 5px 4px var(--ag-checkbox-checked-glow-color);
                &::before {
                    content: '✔';
                    position: absolute;
                    pointer-events: none;
                    inset: 0;
                    text-align: center;
                    line-height: 16px;
                    font-size: 14px;
                }
            }
        }

        .ag-checkbox-input {
            width: 16px;
            height: 16px;
            margin: 0;
            appearance: none;
            -webkit-appearance: none;
            border-radius: 4px;
        
            &:focus {
                box-shadow: 0 0 3px 3px yellow;
                outline: none;
            }
        }
        
        `,
});

const myCustomTheme = themeQuartz.withPart(myCheckboxStyle);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :columnDefs="columnDefs"
      :rowData="rowData"
      :theme="theme"
      :defaultColDef="defaultColDef"
      :initialState="initialState"
      :rowSelection="rowSelection"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "make" },
      { field: "model" },
      { field: "price" },
    ]);
    const rowData = ref<IOlympicData[] | null>(
      (() => {
        const rowData: any[] = [];
        for (let i = 0; i < 10; i++) {
          rowData.push({
            make: "Toyota",
            model: "Celica",
            price: 35000 + i * 1000,
          });
          rowData.push({
            make: "Ford",
            model: "Mondeo",
            price: 32000 + i * 1000,
          });
          rowData.push({
            make: "Porsche",
            model: "Boxster",
            price: 72000 + i * 1000,
          });
        }
        return rowData;
      })(),
    );
    const theme = ref<Theme | "legacy">(myCustomTheme);
    const defaultColDef = ref<ColDef>({
      editable: true,
      flex: 1,
      minWidth: 100,
      filter: true,
    });
    const initialState = ref<GridState>({
      rowSelection: ["1", "2", "3"],
    });
    const rowSelection = ref<RowSelectionOptions | "single" | "multiple">({
      mode: "multiRow",
      checkboxes: true,
    });

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      rowData,
      theme,
      defaultColDef,
      initialState,
      rowSelection,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Creating Parts](https://www.ag-grid.com/examples/theming-distribution/creating-parts/vue3)

#### Choosing A Feature For Your Part

You have three options for `feature`:

- `undefined`, or omit the feature property. In this case once added to a theme the part can not be removed. Many applications choose to bundle all the CSS for a custom theme in one part with no feature set. This is the simplest way of getting the CSS scoping benefits of using parts.
- One of the built-in part features, like `checkboxStyle` or `iconSet`. See the [Parts](https://www.ag-grid.com/vue-data-grid/theming-parts/) page for a full list. Adding the part to any theme will replace the built-in part with the same feature.
- A string of your choice, to use the same part replacement semantics in your own design system. We recommend prefixing the part name with your organisation to prevent name clashes in future grid versions. For example, Acme Corp might have several typography styles, represented as parts with the feature `acmeCorpTypographyStyle`. Your custom theme can bundle a default typography style, and applications can replace it with a different one if they wish.

#### Naming Of Parameters In Custom Parts

Parameters must use a naming convention based on their type, so for example all colour parameters must end with `Color`. The full list of types and suffixes is on the [Parameters](https://www.ag-grid.com/vue-data-grid/theming-parameters/) page. Any variable without a recognised suffix is considered to be a length.

Using the correct type suffix ensures that values will be interpreted correctly, allowing you to use the extended syntax, e.g. `{ref: "accentColor", mix: 0.5}` to create a semi-transparent colour.

Additionally, the suffix is used by Typescript to infer the correct type for the parameter, ensuring that applications using the part and overriding the default value in their theme will get appropriate type checking.

### Multiple Grids

Each grid on the page can have its own theme. In the example below, 3 themes are used by 4 grids. The bottom two grids share a theme (Balham) and use CSS custom properties to achieve different header colours:

#### Multiple Grids

```ts
import { createApp, defineComponent } from "vue";

import type { ColDef } from "ag-grid-community";
import {
  AllCommunityModule,
  ModuleRegistry,
  enableDevValidations,
  themeAlpine,
  themeBalham,
  themeQuartz,
} from "ag-grid-community";
import { AgGridVue } from "ag-grid-vue3";

import "./styles.css";

// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([AllCommunityModule]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%; display: flex; flex-direction: column">
            <div style="display: flex; gap: 16px">
                <p style="flex: 1 1 0%">Quartz theme:</p>
                <p style="flex: 1 1 0%">Alpine theme:</p>
            </div>
            <div style="flex: 1 1 0%; display: flex; gap: 16px">
                <div style="flex: 1 1 0%">
                    <ag-grid-vue
                        style="height: 100%;"
                        :columnDefs="columnDefs"
                        :defaultColDef="defaultColDef"
                        :rowData="rowData"
                        :theme="theme1"
                    ></ag-grid-vue>
                </div>
                <div style="flex: 1 1 0%">
                    <ag-grid-vue
                        style="height: 100%;"
                        :columnDefs="columnDefs"
                        :defaultColDef="defaultColDef"
                        :rowData="rowData"
                        :theme="theme2"
                    ></ag-grid-vue>
                </div>
            </div>
            <div style="display: flex; gap: 16px">
                <p style="flex: 1 1 0%">Balham theme (green header):</p>
                <p style="flex: 1 1 0%">Balham theme (red header):</p>
            </div>
            <div style="flex: 1 1 0%; display: flex; gap: 16px">
                <div style="flex: 1 1 0%;" class="green-header">
                    <ag-grid-vue
                        style="height: 100%;"
                        :columnDefs="columnDefs"
                        :defaultColDef="defaultColDef"
                        :rowData="rowData"
                        :theme="theme3"
                    ></ag-grid-vue>
                </div>
                <div style="flex: 1 1 0%;" class="red-header">
                    <ag-grid-vue
                        style="height: 100%;"
                        :columnDefs="columnDefs"
                        :defaultColDef="defaultColDef"
                        :rowData="rowData"
                        :theme="theme3"
                    ></ag-grid-vue>
                </div>
            </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    return {
      theme1: themeQuartz,
      theme2: themeAlpine,
      theme3: themeBalham,

      columnDefs: <ColDef[]>[
        { field: "make" },
        { field: "model" },
        { field: "price" },
      ],
      defaultColDef: <ColDef>{
        editable: true,
        flex: 1,
        minWidth: 100,
        filter: true,
      },
      rowData: (() => {
        const rowData = [];
        for (let i = 0; i < 10; i++) {
          rowData.push({
            make: "Toyota",
            model: "Celica",
            price: 35000 + i * 1000,
          });
          rowData.push({
            make: "Ford",
            model: "Mondeo",
            price: 32000 + i * 1000,
          });
          rowData.push({
            make: "Porsche",
            model: "Boxster",
            price: 72000 + i * 1000,
          });
        }
        return rowData;
      })(),
    };
  },
});

createApp(VueExample).mount("#app");
```

[Live example: Multiple Grids](https://www.ag-grid.com/examples/theming-distribution/multiple-grids/vue3)
