Skip to main content

KageKit

A declarative UI layer for discord.py Components V2.

Components V2 lets you build anything, which is the problem: every panel ends up re-deciding where the tabs go, which red means "you cannot undo this", and whether a sub-menu should stack a new ephemeral message. KageKit turns those decisions into structure — you describe the panel, and the layout is not yours to get wrong.

from kagekit import Action, ActionBar, Card, Page, Pager, SettingRow, Tab, TabBar, Text

await Page(
    tabs=TabBar(
        tabs=[Tab("Pending", "pending"), Tab("Done", "done")],
        active="pending",
        on_change=self.switch_tab,          # (interaction, value)
    ),
    body=[
        Card(title="🎫 Ticket settings", intent="brand", children=[
            SettingRow("Category", category.name, emoji="📂",
                       action="Change", on_click=self.edit_category),
            SettingRow("Notify", channel.mention, emoji="🔔",
                       action="Change", on_click=self.edit_notify),
        ]),
        Card(title="Delete every ticket", intent="danger", children=[
            Text("This cannot be undone."),
        ]),
    ],
    pager=Pager(current=3, total=12, on_change=self.goto),   # (interaction, page)
    actions=ActionBar(on_reload=self.reload, on_back=self.back),
).edit(interaction)

Install

pip install discord-kagekit

Requires Python 3.11+ and discord.py 2.7+. KageKit imports nothing but discord.py and the standard library.

The layout contract

┌ TabBar ─────────────  outside the container, at the very top
│  [Pending] [Running] [Done]
├ Card ───────────────  Container(accent = intent)
│  ## Heading / setting rows
├ Card ───────────────  a different subject gets its own card
├ Pager ──────────────  ⏮  ◀  [ 3 / 12 ]  ▶  ⏭
└ ActionBar ──────────  🔄 Reload   ◀️ Back   ✖️ Close   outside, at the very bottom
  • Section switches (pending / running / done) change what the page is showing, so they sit above the cards, not inside one.
  • Reload / Back / Close act on the message as a whole, so they sit at the bottom, outside every card.
  • Paging is its own row: the center button reads current / total and opens a modal to jump; the outer buttons step one page and jump to either end. It is separate from the ActionBar because it moves through the contents inside a card.
  • Content that is genuinely different gets its own card, with the accent carrying the intent.
  • Operations edit the same message in place. Stacking a new ephemeral per step is not something the layer offers.

What it guarantees

  • More than five tabs become a select instead of overflowing the five-button row.
  • The active tab renders primary and unclickable; a control with no handler renders disabled rather than as a button that does nothing.
  • A Text after a SettingRow does not leak into that row's Section — a recurring bug when panels are hand-built.
  • The budget is checked before sending: exceeding Discord's 10 top-level slots or 40 components raises LimitError telling you what to cut, instead of an opaque API rejection.

Cards

Child What it is
SettingRow one setting: **{emoji} {label}**: {value} plus a button on the right
Text plain text (write ## yourself for a heading)
Heading a sub-heading; thumbnail= hangs an image off it
Divider a separator line
Actions([Action(...)]) a button row for that card's subject; wraps past five
Select string / role / channel / user / mentionable; always its own row
Control a raw discord.ui.Item, for persistent views the above can't express

Theming

KageKit ships neutral: English labels, no branding, no limits. Everything product-specific is injected.

from kagekit import ComponentBuilder, Labels, Limits, Theme

theme = Theme(
    labels=Labels(back="戻る", close="閉じる", reload="更新"),
    footer="Made with example.com",     # appended as subtext on the last card
)
cb = ComponentBuilder(theme=theme)

Theme.status(enabled) returns the shared 🟢 Enabled / ⚪ Disabled wording, and state_intent(enabled) returns the matching card intent, so state reads the same in text and in colour across every panel.

Palette

Discord's stock colours are highly saturated; four cards in a row become a stack of neon bars. The default palette keeps the hue and drops the saturation to a value that stays legible on both Discord themes.

Token Value Meaning
brand #6F63E0 ordinary panels, the primary action
success #3F9E72 done, enabled
warning #C79141 recoverable warning
danger #C2504F destructive and irreversible
info #4A87A8 informational, in progress
neutral #6E7480 neutral, disabled

DISCORD_CLASSIC keeps the old stock values if you want them back.

The low layer

ComponentBuilder is the method-chaining builder the declarative layer is built on. It is public: reach for it when you need something Page does not model (a persistent custom_id view, a bespoke message), and use render_card(cb, card) to drop a declarative card into a hand-built view.

Limits

Discord caps a message at 10 top-level components and 40 in total, and an action row at 5 buttons. A card that exists only to hold a heading costs about 3 components — worth knowing before you split one panel into six cards.

Contributing

This repository is generated from the bot it lives in — see CONTRIBUTING.md before opening a pull request.

Writing panels with an AI agent? AGENTS.md is the contract in one page.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

discord_kagekit-0.1.0.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

discord_kagekit-0.1.0-py3-none-any.whl (23.7 kB view details)

Uploaded Python 3

File details

Details for the file discord_kagekit-0.1.0.tar.gz.

File metadata

  • Download URL: discord_kagekit-0.1.0.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for discord_kagekit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 dbc8298d71a93210d466191807aa6b63858f1b075e394a53ff8547b6b2f60897
MD5 254e0b44aa36ab78944121835e9783db
BLAKE2b-256 b89160ae12603ed202416f2a4808f9b10ac9a134e75780b6e432458acc2f65b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for discord_kagekit-0.1.0.tar.gz:

Publisher: publish.yml on VorEdgeJP/kagekit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file discord_kagekit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: discord_kagekit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for discord_kagekit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75e15e93d73b97622051671a96b7415df96f3f4e560b505f9bb527184726a6c3
MD5 44efb53cd298a76c27b0b40911ed8ec5
BLAKE2b-256 fcc9a6957fae434fcbecc1f96a649dbfdccd5d217f77ed2e0723b65814a658b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for discord_kagekit-0.1.0-py3-none-any.whl:

Publisher: publish.yml on VorEdgeJP/kagekit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page