## 1. Project Overview & Quickstart (spicetify/cli)

## File: README.md

<h3 align="center">[](https://spicetify.app/)</h3>


---

Command-line tool to customize the official Spotify client.
Supports Windows, MacOS and Linux.



### Features

- Change colors across the User Interface
- Inject CSS for advanced customization
- Inject Extensions to extend functionalities, manipulate UI and control player
- Inject Custom Apps
- Make yourself in control of the Spotify client

### Links

- [Installation](https://spicetify.app/docs/getting-started)
- [Basic Usage](https://spicetify.app/docs/getting-started#basic-usage)

---

### Code Signing Policy

Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/).

---

## File: CustomApps/lyrics-plus/README.md

# Spicetify Custom App

### Lyrics Plus

Show current track lyrics. Current lyrics providers:

- Internal Spotify lyrics service.
- Netease: From Chinese developers and users. Provides karaoke and synced lyrics.
- Musixmatch: A company from Italy. Provided synced lyrics.
- Genius: Provides unsynced lyrics but with description/insight from artists themselves (Disabled and cannot be used as a provider on `1.2.31` and higher).





Different lyrics modes: Karaoke, Synced, Unsynced and Genius. At the moment, only Netease provides karaoke-able lyrics. Mode is automatically falled back, from Karaoke, Synced, Unsynced to Genius when lyrics are not available in that mode.

Right click or Double click at any mode tab to "lock in", so lyric mode won't auto switch. It should show a dot next to mode name when mode is locked. Right click or double click again to unlock



Lyrics in Unsynced and Genius modes can be search and jump to. Hit Ctrl + Shift + F to open search box at bottom left of screen. Hit Enter/Shift+Enter to loop over results.



Choose between different option of displaying Japanese lyrics. (Furigana, Romaji, Hiragana, Katakana)



Customise colors, change providers' priorities in config menu. Config menu locates in Profile Menu (top right button with your user name).

To install, run:

```bash
spicetify config custom_apps lyrics-plus
spicetify apply
```

### Credits

- A few parts of app code are taken from Spotify official app, including SyncedLyricsPage, CSS animation and TabBar. Please do not distribute these code else where out of Spotify/Spicetify context.
- Netease synced lyrics parser is adapted from [mantou132/Spotify-Lyrics](https://github.com/mantou132/Spotify-Lyrics). Give it a Star if you like this app.
- The algorithm for converting Japanese lyrics is based on [Hexenq's Kuroshiro](https://github.com/hexenq/kuroshiro).
- The algorithm for converting Chinese lyrics is based on [BYVoid's OpenCC](https://github.com/BYVoid/OpenCC) via [nk2028's opencc-js](https://github.com/nk2028/opencc-js).
- The algorithm for converting Korean lyrics is based on [fujaru's aromanize-js](https://github.com/fujaru/aromanize-js)
- The algorithm for detecting Simplified Chinese is adapted from [nickdrewe's traditional-or-simplified](https://github.com/nickdrewe/traditional-or-simplified).

## 2. Official Technical Reference & Guides (spicetify/docs)

## File: README.md

# Spicetify Docs

This repository holds the documentation for Spicetify, which can be found [here](https://spicetify.app).

## Contributing

If you feel like you can contribute, please do so by opening an issue or pull request. We are always open to expand our documentation and add new features.

---

## File: docs/development/api-wrapper/functions/add-to-queue.md

---
title: addToQueue
---

Adds a track or array of tracks to the bottom of the prioritized queue.

:::tip

This works similarly to [`Spicetify.Platform.PlayerAPI.addToQueue`](/docs/development/api-wrapper/methods/platform#addtoqueue) but works silently, meaning no notification will be shown.

If you want default Spotify behavior, use [`Spicetify.Platform.PlayerAPI.addToQueue`](/docs/development/api-wrapper/methods/platform#addtoqueue) instead.

:::

```ts
function addToQueue(uri: ContextTrack[]): Promise<void>;
```

#### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| `uri` | [`ContextTrack[]`](/docs/development/api-wrapper/types/context-track) | Array of tracks to add to queue. |

#### Example

```ts
// Add current track to queue
const currentTrack = Spicetify.Player.data.item;

await Spicetify.addToQueue([currentTrack]);

// Add a track to queue
const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh";

await Spicetify.addToQueue([ { uri: trackUri } ]);

---

## File: docs/development/api-wrapper/functions/color-extractor.md

---
title: colorExtractor
---

Extracts colors from a playlist, track, album, artist, show, etc.

```ts
function colorExtractor(uri: string): Promise<{
    DARK_VIBRANT: string;
    DESATURATED: string;
    LIGHT_VIBRANT: string;
    PROMINENT: string;
    VIBRANT: string;
    VIBRANT_NON_ALARMING: string;
}>;
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| uri | `string` | URI of anything that has artwork (playlist, track, album, artist, show, etc.) |

#### Returns

| Name | Type | Description |
| :--- | :--- | :--- |
| DARK_VIBRANT | `string` | Dark vibrant color in hex format. |
| DESATURATED | `string` | Desaturated color in hex format. |
| LIGHT_VIBRANT | `string` | Light vibrant color in hex format. |
| PROMINENT | `string` | Prominent color in hex format. |
| VIBRANT | `string` | Vibrant color in hex format. |
| VIBRANT_NON_ALARMING | `string` | Vibrant non alarming color in hex format. |

#### Example

```ts
// Get color from current track
const currentTrack = Spicetify.Player.data.item;
const colors = await Spicetify.colorExtractor(currentTrack.uri);
```

---

## File: docs/development/api-wrapper/functions/get-audio-data.md

---
title: getAudioData
---

Fetch track analyzed audio data.

Under the hood, it uses the `wg://audio-attributes/v1/audio-analysis/` endpoint, which is identical to Spotify Web API's [Get Track's Audio Analysis](https://developer.spotify.com/documentation/web-api/reference/get-audio-analysis). The only difference is that it doesn't require authentication.

:::caution

Beware, not all tracks have audio data.

:::

```ts
function getAudioData(uri?: string): Promise<any>;
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| uri | `string` &#124; `undefined` | URI of the track. If not provided, it will use the current track. |

#### Returns

An object containing the audio data. See the [Spotify Web API reference](https://developer.spotify.com/documentation/web-api/reference/get-audio-analysis) for more details.

#### Example

```ts
// Get audio data from current track
const audioData = await Spicetify.getAudioData();

// Get audio data from a specific track
const audioData = await Spicetify.getAudioData("spotify:track:1qDrWA6lyx8cLECdZE7TV7");
```

---

## File: docs/development/api-wrapper/functions/get-font-style.md

---
title: getFontStyle
---

Spicetify provides a function that returns the CSS style for a given font variant used in the Spotify app.

:::tip

This function is used to provide backwards compatibility for older Spicetify extensions and custom apps that use `main-type-` classes.

Instead of using this function to get Spotify stylings, you can simply add the `main-type-<variant>` class to your element.

:::

```ts
function getFontStyle(font: Variant): string;
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| font | [`Variant`](/docs/development/api-wrapper/types/variant) | Font variant |

#### Returns

`string` - CSS style for the given font variant.

#### Example

```ts
const style = getFontStyle("forte");

// Returns "viola" if given an invalid variant
// Equivalent to `getFontStyle("viola");`
const style = getFontStyle("invalid-variant");
```

---

## File: docs/development/api-wrapper/functions/remove-from-queue.md

---
title: removeFromQueue
---

:::tip

This works similarly to [`Spicetify.Platform.PlayerAPI.removeFromQueue`](/docs/development/api-wrapper/methods/platform#removefromqueue).

:::

:::caution

If a `uid` is not provided, all tracks with the same `uri` will be removed.

:::

```ts
function removeFromQueue(uri: ContextTrack[]): Promise<void>;
```

#### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| `uri` | [`ContextTrack[]`](/docs/development/api-wrapper/types/context-track) | Array of tracks to remove from queue. |

#### Example

```ts
// Remove current track from queue
const currentTrack = Spicetify.Player.data.item;

await Spicetify.removeFromQueue([currentTrack]);

// Remove a track from queue
const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh";

await Spicetify.removeFromQueue([ { uri: trackUri } ]);
```

---

## File: docs/development/api-wrapper/functions/show-notification.md

---
title: showNotification
---

Show a toast notification inside Spotify.

```ts
function showNotification(text: string, isError?: boolean, msTimeout?: number): void;
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| text | `string` | Message to display. Can use inline HTML for styling. |
| isError | `boolean` | If true, toast will be red. Defaults to false. |
| msTimeout | `number` | Time in milliseconds to display the toast. Defaults to Spotify's value. |

#### Example

```ts
// Display a notification
Spicetify.showNotification("My Menu Item clicked!");

// Display a notification with a custom timeout
Spicetify.showNotification("My Menu Item clicked!", false, 1000);

// Display an error notification
Spicetify.showNotification("Something wrong happened", true);

// Display a bolded error notification
Spicetify.showNotification("**Something wrong happened**", true);
```

---

## File: docs/development/api-wrapper/classes/context-menu.md

---
title: ContextMenu
---

Create custom menu item and prepend to right click context menu.

Useful for adding custom actions to context menu (when a user right-clicks on a track, album, artist, etc.)

## Classes

### Item

Single context menu item.


```ts
new Spicetify.ContextMenu.Item(
  name: string,
  onClick: OnClickCallback,
  shouldAdd?: ShouldAddCallback,
  icon?: SVGIcon | string,
  disabled?: boolean,
)
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| onClick | `OnClickCallback` | Callback function when the menu item is clicked. |
| shouldAdd | `ShouldAddCallback` | Callback function to determine if the menu item should be added. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the menu item. |
| disabled | `boolean` | Whether the menu item is disabled. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| iconList | [`readonly SVGIcon[]`](/docs/development/api-wrapper/types/svgicon) | List of icons. |
| name | `string` | Name of the menu item. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon at the end of the menu item. |
| disabled | `boolean` | Whether the menu item is disabled. |
| shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |
| onClick | [`OnClickCallback`](/docs/development/api-wrapper/types/context-menu/onclick-callback) | Callback function when the menu item is clicked. |

#### Methods

##### `register`

Register the menu item to context menu.

```ts
register(): void
```

##### `deregister`

Remove the menu item from context menu.

```ts
deregister(): void
```
#### Example

```ts
// This function will determine if the selected item is a track
function ifItemIsTrack(uri) {
  let uriObj = Spicetify.URI.fromString(uri[0]);
  switch (uriObj.type) {
    case Type.TRACK:
      return true;
  }
  return false;
}

// Create a new menu item that only appears when a track is selected
const menuItem = new Spicetify.ContextMenu.Item(
  "My Menu Item",
  () => {
    Spicetify.showNotification("My Menu Item clicked!");
  },
  ifItemIsTrack,
  Spicetify.SVGIcons["play"],
  false,
);

// Register the menu item
menuItem.register();

// Deregister the menu item
menuItem.deregister();

// Change the menu item's name
menuItem.name = "My New Menu Item";

// Change the menu item's icon
menuItem.icon = "pause"
```

### SubMenu

Create a sub menu to contain `Item`s.

`Item`s in `subItems` array shouldn't be registered.


```ts
new Spicetify.ContextMenu.SubMenu(
  name: string,
  subItems: Iterable,
  shouldAdd?: ShouldAddCallback,
  disabled?: boolean,
)
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| subItems | [`Iterable`](#item) | Array of `Item`s to be added to the sub menu. |
| shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |
| disabled | `boolean` | Whether the menu item is disabled. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| disabled | `boolean` | Whether the menu item is disabled. |
| shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |

#### Methods

##### `addItem`

Add an `Item` to the sub menu.

```ts
addItem(item: Item): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| item | [`Item`](#item) | `Item` to be added to the sub menu. |

##### `removeItem`

Remove an `Item` from the sub menu.

```ts
removeItem(item: Item): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| item | [`Item`](#item) | `Item` to be removed from the sub menu. |

##### `register`

Register the sub menu to context menu.

```ts
register(): void
```

##### `deregister`

Remove the sub menu from context menu.

```ts
deregister(): void
```

#### Example

```ts
// Create a new menu item
const menuItem = new Spicetify.ContextMenu.Item(
  "My Menu Item",
  () => {
    Spicetify.showNotification("My Menu Item clicked!");
  },
  () => true,
  Spicetify.SVGIcons["play"],
  false,
);

// Create a new sub menu
const subMenu = new Spicetify.ContextMenu.SubMenu(
  "My Sub Menu",
  [menuItem],
  () => true,
  false,
);

// Register the sub menu
subMenu.register();

// Deregister the sub menu
subMenu.deregister();

// Change the sub menu's name
subMenu.name = "My New Sub Menu";

// Add a new menu item to the sub menu
subMenu.addItem(new Spicetify.ContextMenu.Item(
  "My New Menu Item",
  () => {
    Spicetify.showNotification("My New Menu Item clicked!");
  },
  () => true,
  Spicetify.SVGIcons["play"],
  false,
));
```

---

## File: docs/development/api-wrapper/classes/menu.md

---
title: Menu
---

Create and prepend custom menu items in the profile menu.

## Classes

### Item

Single menu item.

```ts
new Spicetify.Menu.Item(
  name: string,
  isEnabled: boolean,
  onClick: (self: Item) => void,
  icon?: SVGIcon | string,
)
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| isEnabled | `boolean` | Whether the menu item is enabled. |
| onClick | `(self: Item) => void` | Callback function when the menu item is clicked. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the menu item. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| isEnabled | `boolean` | Whether the menu item is enabled. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the menu item. |

#### Methods

##### setName

Set the label of the menu item.

```ts
setName(name: string): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |

##### setState

Set the state of the menu item. The item will have a tick icon next to it if its state is enabled.

```ts
setState(isEnabled: boolean): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| isEnabled | `boolean` | Whether the menu item is enabled. |

##### setIcon

Set the icon at the end of the menu item.

```ts
setIcon(icon: SVGIcon | string): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the menu item. |

##### register

Register the menu item to the profile menu.

```ts
register(): void
```

##### deregister

Remove the menu item from the profile menu.

```ts
deregister(): void
```

#### Example

```ts
const item = new Spicetify.Menu.Item("My Item", true, () => {
  console.log("My Item is clicked");
});

item.register();

// item.name = "My Item (Updated)";
item.setName("My Item (Updated)");

// item.isEnabled = false;
item.setState(false);

// item.icon = "heart";
item.setIcon("heart");
```

### SubMenu

Create a sub menu to contain `Item` toggles.

`Item`s in `subItems` array shouldn't be registered.

```ts
new Spicetify.Menu.SubMenu(
  name: string,
  subItems: Item[],
)
```

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |
| subItems | [`Item[]`](/docs/development/api-wrapper/classes/menu#item) | Array of sub menu items. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |

#### Methods

##### setName

Set the label of the menu item.

```ts
setName(name: string): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| name | `string` | Name of the menu item. |

##### addItem

Add a sub menu item.

```ts
addItem(item: Item): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| item | [`Item`](/docs/development/api-wrapper/classes/menu#item) | Sub menu item. |

##### removeItem

Remove a sub menu item.

```ts
removeItem(item: Item): void
```

| Parameter | Type | Description |
| :--- | :--- | :--- |
| item | [`Item`](/docs/development/api-wrapper/classes/menu#item) | Sub menu item. |

##### register

Register the menu item to profile menu.

```ts
register(): void
```

##### deregister

Remove the menu item from profile menu.

```ts
deregister(): void
```

#### Example

```ts
const item1 = new Spicetify.Menu.Item("My Item 1", true, () => {
  console.log("My Item 1 is clicked");
});

const item2 = new Spicetify.Menu.Item("My Item 2", true, () => {
  console.log("My Item 2 is clicked");
});

const subMenu = new Spicetify.Menu.SubMenu("My Sub Menu", [item1, item2]);

subMenu.register();

// subMenu.name = "My Sub Menu (Updated)";
subMenu.setName("My Sub Menu (Updated)");

// subMenu.addItem(item3);
subMenu.addItem(
  new Spicetify.Menu.Item("My Item 3", true, () => {
    console.log("My Item 3 is clicked");
  })
);
```

---

## File: docs/development/api-wrapper/classes/playbar.md

---
title: Playbar
---

Create buttons in the player.

```ts
namespace Playbar {
    class Button {
        constructor(label: string, icon: SVGIcon | string, onClick: (self: Button) => void, disabled?: boolean, active?: boolean, registerOnCreate?: boolean);
        label: string;
        icon: string;
        onClick: (self: Button) => void;
        disabled: boolean;
        active: boolean;
        element: HTMLButtonElement;
        tippy: any;
        register: () => void;
        deregister: () => void;
    }

    class Widget {
        constructor(label: string, icon: SVGIcon | string, onClick?: (self: Widget) => void, disabled?: boolean, active?: boolean, registerOnCreate?: boolean);
        label: string;
        icon: string;
        onClick: (self: Widget) => void;
        disabled: boolean;
        active: boolean;
        element: HTMLButtonElement;
        tippy: any;
        register: () => void;
        deregister: () => void;
    }
};
```

## `Button`

Create buttons next to the player extra control buttons (e.g. queue, lyrics, Now Playing View, etc.).

This is useful for creating buttons whose actions have an impact on or relate to the player, and are generally dynamic/stateful, such as a button that toggles the player's loop mode.

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| label | `string` | Label of the button. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the button. |
| onClick | `(self: Button) => void` | Callback function when the button is clicked. |
| disabled | `boolean` &#124; `undefined` | Whether the button is disabled. |
| active | `boolean` &#124; `undefined` | Whether the button is active. |
| registerOnCreate | `boolean` &#124; `undefined` | Whether the button should be registered to the player on creation. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| label | `string` | Label of the button. |
| icon | `string` | Icon of the button. |
| disabled | `boolean` | Whether the button is disabled. |
| active | `boolean` | Whether the button is active. |
| onClick | `(self: Button) => void` | Callback function when the button is clicked. |
| element | `HTMLButtonElement` | HTML element of the button. |
| tippy | `any` | Tippy instance of the button. For more information, see [Tippy.js](https://atomiks.github.io/tippyjs/v6/tippy-instance/). |

#### Methods

##### `register`

Register the button to the player.

```ts
register(): void;
```

##### `deregister`

Deregister the button from the player.

```ts
deregister(): void;
```

#### Example

:::caution

Tippy, `onclick` or any other click events will **not** work if `disabled` is set to `true`. You will need to manually enable the button inside your extension.

This is due to the limitations of Tippy itself and how HTML elements work.

:::

```ts
// By default, the button will be registered to the player on creation.
// You can disable this by setting registerOnCreate to false.
// Each button comes with a preconfigured Tippy instance that aims to mimic the original Spotify tooltip.
const button = new Spicetify.Playbar.Button(
    "My Button",
    "play",
    (self) => {
        // Do something when the button is clicked.
    },
    false, // Whether the button is disabled.
    false, // Whether the button is active.
);

// You can also register the button to the player later.
button.register();

// Remove the button from the player when it is no longer needed.
button.deregister();
// If you don't want to remove the button entirely, you can also disable it.
button.disabled = true;

// Change button properties.
// Changing label will also change the tooltip content.
button.label = "Hello world!";
button.icon = "play";

// You can also set properties of the HTML element.
button.element.style.color = "red";
button.element.oncontextmenu = () => {
    Spicetify.showNotification("You right-clicked me!");
};
button.element.addEventListener("click", () => {
    // Do something else.
    Spicetify.showNotification("You clicked me!");
});

// You can also change properties of the Tippy instance. For more information, see https://atomiks.github.io/tippyjs/v6/tippy-instance/.
button.tippy.setContent("Hello world!");

// Or if you want to use HTML.
button.tippy.setProps({
    content: "**Hello world!**",
    allowHTML: true,
});
```

## `Widget`

Create widgets in the player, next to track information similar to the Heart button.

This is useful for creating buttons whose actions have an impact on the state of the player and the track being played, such as a button that adds the current track to a playlist.

#### Parameters

| Parameter | Type | Description |
| :--- | :--- | :--- |
| label | `string` | Label of the widget. |
| icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) &#124; `string` | Icon of the widget. |
| onClick | `(self: Widget) => void` | Callback function when the widget is clicked. |
| disabled | `boolean` &#124; `undefined` | Whether the widget is disabled. |
| active | `boolean` &#124; `undefined` | Whether the widget is active. |
| registerOnCreate | `boolean` &#124; `undefined` | Whether the widget should be registered to the player on creation. |

#### Properties

:::tip

All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.

:::

| Name | Type | Description |
| :--- | :--- | :--- |
| label | `string` | Label of the widget. |
| icon | `string` | Icon of the widget. |
| disabled | `boolean` | Whether the widget is disabled. |
| active | `boolean` | Whether the widget is active. |
| onClick | `(self: Widget) => void` | Callback function when the widget is clicked. |
| element | `HTMLButtonElement` | HTML element of the widget. |
| tippy | `any` | Tippy instance of the widget. For more information, see [Tippy.js](https://atomiks.github.io/tippyjs/v6/tippy-instance/). |

#### Methods

##### `register`

Register the widget to the player.

```ts
register(): void;
```

##### `deregister`

Deregister the widget from the player.

```ts
deregister(): void;
```

#### Example

:::caution

Tippy, `onclick` or any other click events will **not** work if `disabled` is set to `true`. You will need to manually enable the widget inside your extension.

This is due to the limitations of Tippy itself and how HTML elements work.

:::

```ts
// By default, the widget will be registered to the player on creation.
// You can disable this by setting registerOnCreate to false.
// Each widget comes with a preconfigured Tippy instance that aims to mimic the original Spotify tooltip.
const widget = new Spicetify.Playbar.Widget(
    "My Widget",
    "play",
    (self) => {
        // Do something when the widget is clicked.
    },
    false, // Whether the widget is disabled.
    false, // Whether the widget is active.
);

// You can also register the widget to the player later.
widget.register();

// Remove the widget from the player when it is no longer needed.
widget.deregister();

// Change widget properties.
// Changing label will also change the tooltip content.
widget.label = "Hello world!";
widget.icon = "play";

// You can also set properties of the HTML element.
widget.element.style.color = "red";
widget.element.oncontextmenu = () => {
    Spicetify.showNotification("You right-clicked me!");
};
widget.element.addEventListener("click", () => {
    // Do something else.
    Spicetify.showNotification("You clicked me!");
});

// You can also change properties of the Tippy instance. For more information, see https://atomiks.github.io/tippyjs/v6/tippy-instance/.
widget.tippy.setContent("Hello world!");

// Or if you want to use HTML.
widget.tippy.setProps({
    content: "**Hello world!**",
    allowHTML: true,
});
```