Skip to main content

What is Settings?

settings is the registry of settings screens. Register an entry and it becomes a real route in Discord’s settings navigation, listed under the Unbound section alongside the built-in General, Plugins, Design, and Developer pages. It is a registry of screens, not of values. Persisting what those screens read and write is storage’s job.
Most plugins don’t need this module. A plugin that exports getSettingsPanel already gets a settings button on its card in the Plugins list, and Unbound renders the returned node on a screen for you. Reach for registerSettings when you want a top-level entry of your own in the settings list, separate from your plugin’s card.

Registering a screen

registerSettings takes one or more entries and adds them to the registry. Entries are keyed, so registering the same key twice overwrites the previous entry and logs a warning.
Register in your plugin’s start and call removeSettings with the same key in stop. Entries are not cleaned up for you, so a disabled plugin otherwise leaves a dead route behind.

The entry shape

An entry mirrors Discord’s SETTING_RENDERER_CONFIG route shape, which is why it looks the way it does.
'route'
required
Always 'route'. Routes are the only entry kind Unbound registers.
string
required
Unique identifier for the entry, and the key removeSettings deletes by. Built-ins use screaming snake case (UNBOUND_GENERAL); namespace yours so it can’t collide.
() => string
required
Hook returning the title shown in the list and the screen header. Being a hook, it can pull from i18n or from storage and re-render when either changes.
string | null
required
The key of the parent route, or null for a top-level entry. Built-ins pass null.
SettingsScreen
required
The screen this route renders.
string
The section label the entry is grouped under in the settings overview. Built-ins use 'Unbound'.
() => boolean
Hook deciding whether the entry is shown. The built-in Developer page uses this to appear only while developer mode is on.
boolean
Hides the entry from the settings list while keeping the route navigable. Use it for screens you push to programmatically rather than ones the user picks from a list.
ComponentType<any>
Component rendered as the row’s leading icon. Built-ins render Discord’s TableRowIcon with an id resolved through assets.

Conditional and hidden entries

usePredicate is a hook, so it can subscribe to storage and hide or show the entry as settings change. This is how the Developer page appears only once developer mode is enabled.

Removing and inspecting

sections() returns only entries registered through this API. Unbound’s own built-in screens are merged in separately when the navigation config is read, so they don’t appear in the result.

Settings vs storage

The two modules are complementary and it’s worth keeping them straight: A settings screen almost always uses both: settings puts the screen in the list, and storage holds what the controls on it read and write. Build the screen itself out of components, and see creating an addon for where the registration goes in a plugin’s lifecycle. Addon enabled-state is persisted by the managers, not by this module.