Panel
Spicetify provides a wrapper for the Spotify PanelAPI method to make it easier to use, as well as providing a method to help you register your own panel.
namespace Panel { const reservedPanelIds: Record<string | number, string | number>; const Components: { PanelSkeleton: any; PanelContent: any; PanelHeader: any; }; function hasPanel(id: number): boolean; function getPanel(id: number): React.ReactNode | undefined; function setPanel(id: number): Promise<void>; function subPanelState(callback: (id: number) => void): void; function registerPanel(props: PanelProps): { id: number; toggle: () => Promise<void>; onStateChange: (callback: (isActive: boolean) => void) => void; isActive: boolean; }; const currentPanel: number;}Internally, Spotify uses an enum to cross-reference the IDs of the panels with the panels themselves. As such, all methods in Panel will only accept IDs that are reserved by Spotify and those that are manually registered via registerPanel.
Properties
reservedPanelIds
An object of reserved panel IDs used by Spotify.
const reservedPanelIds: Record<string | number, string | number>;This list is dynamic, so it is recommended to check the list in the console.
As of Spotify 1.2.12, there are currently 5 reserved IDs:
{ 0: "Disabled", 1: "BuddyFeed", 2: "NowPlayingView", 3: "WhatsNewFeed", 4: "Puffin",}Components
Collection of React Components used by Spotify in the Panel.
Refer to Registering a custom Panel for more information on how to use these components.
const Components: { PanelSkeleton: any; PanelContent: any; PanelHeader: any;};currentPanel
ID of the current Panel.
const currentPanel: number;Example:
console.log(Spicetify.Panel.currentPanel); // 0Methods
hasPanel
Check whether or not a Panel with the provided ID is registered.
function hasPanel(id: number): boolean;Example:
Spicetify.Panel.hasPanel(0); // true, reserved to "Disabled" by SpotifySpicetify.Panel.hasPanel('Disabled'); // false, ID is not a numberSpicetify.Panel.hasPanel(5); // false, ID is not registeredgetPanel
Get the Panel with the provided ID.
function getPanel(id: number): React.ReactNode | string | undefined;Example:
Spicetify.Panel.getPanel(0); // "Disabled"Spicetify.Panel.getPanel('Disabled'); // undefined, ID is not a numberSpicetify.Panel.getPanel(5); // undefined, ID is not registeredsetPanel
Set the Panel state with the provided ID.
function setPanel(id: number): Promise<void>;Example:
await Spicetify.Panel.setPanel(0); // Close the Panel
await Spicetify.Panel.setPanel(1); // Open BuddyFeed
// Open the Panel with ID 5// If the ID is not registered, it will be set to 0await Spicetify.Panel.setPanel(5);subPanelState
Subscribe to Panel changes.
function subPanelState(callback: (id: number) => void): void;Example:
Spicetify.Panel.subPanelState((id) => { console.log(id); // 2 // Do something});registerPanel
Register a new Panel and return its methods and properties.
function registerPanel(props: PanelProps): { id: number; toggle: () => Promise<void>; onStateChange: (callback: (isActive: boolean) => void) => void; isActive: boolean;};Parameters
| Name | Type | Description |
|---|---|---|
props | PanelProps | Properties of the Panel |
Example:
const { id, toggle, onStateChange, isActive } = Spicetify.Panel.registerPanel({ label: 'My Panel', children: <div>My Panel</div>,});
console.log(id); // 5console.log(isActive); // false
await toggle(); // Open the Panel
console.log(isActive); // true
onStateChange((isActive) => { console.log(isActive); // false});Registering a custom Panel
Ideally, you would not need to use these components directly, but in case the registerPanel method does not satisfy your needs, you can use these along with the isCustom prop to create your own customised panel.
Props
See PanelHeaderProps, PanelContentProps, and PanelSkeletonProps.
Example
const PanelAction = () => { return ( <Spicetify.ReactComponent.TooltipWrapper label="Show notification"> <button onClick={() => Spicetify.showNotification('Hello World')}> <Spicetify.ReactComponent.IconComponent semanticColor="textBase" dangerouslySetInnerHTML={{ __html: Spicetify.SVGIcons["play"] }} iconSize={16} /> </button> </Spicetify.ReactComponent.TooltipWrapper> )}
// Ideally, you would want to memoize this component// to prevent unnecessary re-renders if you were to pass props
// Props will have a single `panel` property for the panel IDconst Panel = ({ panel }) => { // For example, if you want to change the header title const [title, setTitle] = React.useState('Hello World'); // Or if you want to display extra actions on the header in a stateful manner const [showActions, setShowActions] = React.useState(false);
return ( <Spicetify.ReactComponent.PanelSkeleton label="Hello World" style={{ "--panel-width": "300px" }} > <Spicetify.ReactComponent.PanelContent className="my-panel-content"> <Spicetify.ReactComponent.PanelHeader title={title} link="/collection" // Can be an URI or an external URL panel={panel} actions={showActions && <PanelAction />} onClose={() => Spicetify.showNotification('Closed')} onBack={() => Spicetify.showNotification('Back')} /> <div className="my-panel-body"> Hello World </div> <button onClick={() => setTitle('Hello World 2')}>Change title</button> <button onClick={() => setShowActions(!showActions)}>Toggle actions</button> </Spicetify.ReactComponent.PanelContent> </Spicetify.ReactComponent.PanelSkeleton> )};
// Finally, register the Panelconst { id, toggle, onStateChange, isActive } = Spicetify.Panel.registerPanel({ children: <Panel />, isCustom: true});