npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

discord-tsx-builder

v1.1.0

Published

Represent Discord Embeds and Components using tsx instead of builders (slow) or json (unreadable)

Readme

discord-tsx-builder

alt text

Represent Discord Embeds and Components using TSX instead of raw JSON or long builder chains.

Install

npm install discord-tsx-builder
pnpm add discord-tsx-builder
yarn add discord-tsx-builder

Use in another project

discord-tsx-builder is a normal npm library. In your own project:

  1. Install discord-tsx-builder
  2. Set TS JSX runtime config
  3. Write TSX with discord-tsx-builder tags
  4. Recommended: run postbuild transform to bake payload objects into built JS

TS config

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "discord-tsx-builder",
    "moduleResolution": "nodenext"
  }
}

moduleResolution: "nodenext" (or node16/bundler) is important so discord-tsx-builder/jsx-runtime resolves correctly.

Postbuild vs Runtime Speed

For the same, exactly same code, we got these results alt text

Postbuild mode (Highly Recommended)

After tsc, run the transformer:

discord-tsx-builder-postbuild ./dist

This rewrites compiled _jsx/_jsxs trees rooted at <DiscordEmbed> / <DiscordComponent> into object literals directly in emitted JS.

Example:

<Text>hello</Text> becomes:

{ type: 10, content: "hello" }

Suggested scripts in consumer project:

{
  "scripts": {
    "build": "tsc",
    "postbuild": "discord-tsx-builder-postbuild ./dist"
  }
}

Runtime mode (Not recommended)

TSX is converted to object payloads when code executes.

import { DiscordEmbed, Title, Description } from "discord-tsx-builder";

const name = "World";
const embed = (
  <DiscordEmbed color="#ffffff">
    <Title>Discord Tsx Builder Testing</Title>
    <Description>Hello {name}</Description>
  </DiscordEmbed>
);

// embed is plain JSON-like data at runtime

Tag reference

All tags are exported from discord-tsx-builder.

Embed root

Use <DiscordEmbed> as the root.

Props:

  • color?: string | number ("#ffffff" or 16777215)

Supported children:

  • <Title>
  • <Description>
  • <Url>
  • <Timestamp>
  • <Color>
  • <Author>
  • <Footer>
  • <Image>
  • <Thumbnail>
  • <Fields>
  • <Field>

Embed tags

<Title>:

  • Children text -> title

<Description>:

  • Children text -> description

<Url>:

  • url prop or children text -> url

<Timestamp>:

  • value prop or children text -> timestamp

<Color>:

  • value prop or children text -> color (hex strings are converted to int)

<Image>:

  • url prop or children text -> image.url

<Thumbnail> (inside embed):

  • url or src prop or children text -> thumbnail.url

<Author>:

  • Props: name, iconUrl (icon_url also accepted), url
  • Children alternatives: <AuthorName>, <AuthorIconUrl>, <AuthorUrl>

<Footer>:

  • Props: text, iconUrl (icon_url also accepted)
  • Children alternatives: <FooterText>, <FooterIconUrl>

<Fields>:

  • Grouping wrapper for <Field>

<Field>:

  • Props: name, value, inline
  • Or children: <FieldName>, <FieldValue>
  • Requires both name and value

Components root

Use <DiscordComponent> as the root. It returns:

  • { components: [...] } for legacy-only layouts
  • { components: [...], flags: 32768 } when v2 components are used

If you are setting components in a response, set the components and the flags separately. interaction.reply({ components: components.components, flags: components.flags })

Legacy components

<ActionRow>:

  • Children: interactive components only (<Button> or any select menu)
  • Select rule: a select menu must be the only child in the row
  • Button rule: max 5 buttons in the row

<Button>:

  • Props: customId, style, label, emoji, url, disabled, skuId
  • If label is omitted, children text becomes label
  • style accepts number or one of: primary, secondary, success, danger, link, premium

<StringSelectMenu>:

  • Props: customId, placeholder, minValues, maxValues, disabled
  • Options can come from options prop array or <Option> children

<UserSelectMenu>, <RoleSelectMenu>, <MentionableSelectMenu>, <ChannelSelectMenu>:

  • Props: customId, placeholder, minValues, maxValues, disabled, defaultValues
  • <ChannelSelectMenu> also supports channelTypes

<Option>:

  • Props: label, value, description, emoji, default
  • Used by <StringSelectMenu>

V2 components

<Container>:

  • Props: accentColor (accent_color also accepted), spoiler
  • Children supported: <Text>, <Section>, <MediaGallery>, <File>, <Separator>, <ActionRow>, <Button>, select menus
  • If <Button>/select appears directly, it is wrapped into an action row automatically

<Text>:

  • Children text -> { type: 10, content: ... }

<Section>:

  • Needs at least one text block
  • Text via direct text, <Text>, or <SectionText>
  • Accessory via <SectionAccessory> with one child: <Button> or <Thumbnail>

<Thumbnail> (inside section accessory or top-level v2):

  • Props: url or src, optional description, spoiler

<MediaGallery>:

  • Props: items array (optional)
  • Or <MediaItem> children

<MediaItem>:

  • Props: url or src, optional description, spoiler

<File>:

  • Props: url or src

<Separator>:

  • Props: divider, spacing

Top-level children allowed in <DiscordComponent>

  • Legacy: <ActionRow>
  • V2: <Container>, <Section>, <Text>, <Thumbnail>, <MediaGallery>, <File>, <Separator>
  • Interactive tags at top-level (<Button> or select menus) are auto-wrapped into action rows and treated as v2

See full usage in:

How Babel is handled

You do not need Babel config in your app.

  • Your app still builds with tsc (or your normal TS pipeline).
  • discord-tsx-builder runtime mode needs no Babel.
  • discord-tsx-builder-postbuild internally uses Babel parser/traverse/generator APIs to parse emitted JS and rewrite only the Discord TSX runtime call trees.
  • Those Babel packages are regular runtime dependencies of discord-tsx-builder, so running the CLI in another project works after install.

So: no .babelrc, no Babel plugin setup, no manual AST wiring in your project.

Comparison (raw JSON vs builders vs discord-tsx-builder)

See:

Validation rules

  • Select menus inside <ActionRow> must be the only child in that row.
  • V2 components automatically set message flag 32768 (IsComponentsV2).

Local example commands

yarn examples:check
yarn examples:runtime
yarn examples:postbuild

Tests

yarn test:runtime
yarn test:build
yarn test