Build JSON object for Slack Block Kit surfaces from readable JSX.
👉 Try our REPL demo in https://speee-jsx-slack.netlify.com/.
- Block Kit as components - Build contents for any surfaces by composing components for Block Kit with JSX.
- HTML-like formatting - Keep a readability by using well-known elements.
See references to dive into jsx-slack deeply.
When developing Slack-integrated app, continuous maintenance of the rich contents is a difficult task. A team member must read and write JSON with deep knowledge about specifications of payload for Slack API.
Slack has shipped Block Kit and Block Kit Builder, and efforts to develop app easily. We believe well-known JSX-based template would enhance a developer experience of Slack app to the next stage.
A project goal is creating an interface to compose maintainable contents for Slack with confidence via readable JSX.
jsx-slack would allow composing blocks with predictable HTML-like markup. It helps in understanding the structure of complex contents and interactions.
We require Node.js >= 10. If you are using TypeScript, we also require TS >= 3.0.
# npm
npm install --save @speee-js/jsx-slack
# yarn
yarn add @speee-js/jsx-slack
Do you hate troublesome setting up for JSX? All right. We provide jsxslack
tagged template literal to build blocks right out of the box. It will generate JSX element, or JSON for Slack API if serializable.
It allows the template syntax almost same as JSX, powered by HTM (Hyperscript Tagged Markup). Setting for transpiler and importing built-in components are not required.
This is a simple example of the template function just to say hello to someone.
import { jsxslack } from '@speee-js/jsx-slack'
export default function exampleBlock({ name }) {
return jsxslack`
<Blocks>
<Section>
Hello, <b>${name}</b>!
</Section>
</Blocks>
`
}
When you want to use jsx-slack with JSX transpiler (Babel / TypeScript), you have to set up to use imported our parser JSXSlack.h
. Typically, we recommend to use pragma comment /** @jsx JSXSlack.h */
.
/** @jsx JSXSlack.h */
import JSXSlack, { Blocks, Section } from '@speee-js/jsx-slack'
export default function exampleBlock({ name }) {
return (
<Blocks>
<Section>
Hello, <b>{name}</b>!
</Section>
</Blocks>
)
}
A prgama would work in Babel (@babel/plugin-transform-react-jsx) and TypeScript with --jsx react
. You can use jsx-slack in either one.
ℹ️ A returned value from JSX is a virtual node prepared for JSON. The node of block containers will be serialized to JSON on calling
JSON.stringify()
. You can also create JSON object from passed node explicitly by wrapping JSX byJSXSlack(<Blocks>...</Blocks>)
.
After than, just use created template in Slack API. We are using the official Node SDK @slack/web-api
in this example. See also Slack guide.
import { WebClient } from '@slack/web-api'
import exampleBlock from './example'
const web = new WebClient(process.env.SLACK_TOKEN)
web.chat
.postMessage({
channel: 'C1232456',
blocks: exampleBlock({ name: 'Yuki Hattori' }),
})
.then((res) => console.log('Message sent: ', res.ts))
.catch(console.error)
It would post a simple Slack message like this:
Slack has recommended to use Block Kit for building tempting messages and modals.
By using jsx-slack, you can build a template with piling up Block Kit blocks by JSX. It is feeling like using components in React or Vue.
<Blocks>
<Section>
<p>Enjoy building blocks!</p>
<blockquote>
<b>
<a href="https://github.com/speee/jsx-slack">@speee-js/jsx-slack</a>
</b>
<br />
<i>Build JSON for Slack Block Kit from JSX</i>
</blockquote>
<Image src="https://github.com/speee.png" alt="Speee, Inc." />
</Section>
<Context>
Maintained by <a href="https://github.com/yhatt">Yuki Hattori</a>
<img src="https://github.com/yhatt.png" alt="yhatt" />
</Context>
<Divider />
<Actions>
<Button url="https://github.com/speee/jsx-slack">GitHub</Button>
<Button url="https://www.npmjs.com/package/@speee-js/jsx-slack">npm</Button>
</Actions>
</Blocks>
<Modal title="My first modal" close="Cancel">
<Section>
<p>
<strong>It's my first modal!</strong> :sunglasses:
</p>
<p>jsx-slack also has supported Slack Modals.</p>
</Section>
<Divider />
<Input type="text" name="subject" label="Subject" required />
<Textarea name="message" label="Message" maxLength={500} />
<ConversationsSelect
name="shareWith"
label="Share with..."
required
include={['public', 'im']}
excludeBotUsers
responseUrlEnabled
/>
<Input type="hidden" name="postId" value="xxxx" />
<Input type="submit" value="Send" />
</Modal>
<Home>
<Image src="https://source.unsplash.com/random/960x240?home" alt="home" />
<Section>
<b>Welcome back to my home!</b> :house_with_garden:
</Section>
<Divider />
<Section>What's next?</Section>
<Actions>
<RadioButtonGroup value="tickets">
<RadioButton value="tickets">
<b>See assigned tickets</b> :ticket:
<small>
<i>Check your tickets to start your work.</i>
</small>
</RadioButton>
<RadioButton value="reminder">
<b>Remind a task later</b> :memo:
<small>
<i>I'll remember a task for you.</i>
</small>
</RadioButton>
<RadioButton value="pomodoro">
<b>Start pomodoro timer</b> :tomato:
<small>
<i>Get focused on your time, with tomato!</i>
</small>
</RadioButton>
</RadioButtonGroup>
<Button actionId="start" style="primary">
Start working
</Button>
</Actions>
</Home>
As like as React, jsx-slack provides <Fragment>
(<JSXSlack.Fragment>
) component for higher-order component (HOC) consited of multiple blocks or elements.
For example, you can define the custom block by grouping some blocks with <Fragment>
if you were using JSX transpiler.
Let's say defines <Header>
custom block that is consisted by <Section>
and <Divider>
.
/** @jsx JSXSlack.h */
import JSXSlack, { Fragment } from '@speee-js/jsx-slack'
const Header = ({ children }) => (
<Fragment>
<Section>
<b>{children}</b>
</Section>
<Divider />
</Fragment>
)
Now the defined block can use in <Blocks>
as like as the other blocks:
<Blocks>
<Header>
<i>jsx-slack custom block</i> :sunglasses:
</Header>
<Section>Let's build your block.</Section>
</Blocks>
If you want to use the short syntax <></>
for fragments in Babel transpiler, we recommend to set an extra pragma command /** @jsxFrag JSXSlack.Fragment */
.
/** @jsx JSXSlack.h */
/** @jsxFrag JSXSlack.Fragment */
import JSXSlack from '@speee-js/jsx-slack'
const Header = ({ children }) => (
<>
<Section>
<b>{children}</b>
</Section>
<Divider />
</>
)
⚠️ TypeScript cannot customize the factory method for fragment syntax. (Microsoft/TypeScript#20469) Please use<Fragment>
component as usual.
jsxslack
template literal tag has built-in fragments support so <Fragment>
does not have to use.
// Header.js
import { jsxslack } from '@speee-js/jsx-slack'
const Header = ({ children }) => jsxslack`
<Section>
<b>${children}</b>
</Section>
<Divider />
`
export default Header
A defined component may use in jsxslack
tag as below:
import { jsxslack } from '@speee-js/jsx-slack'
import Header from './Header'
console.log(jsxslack`
<Blocks>
<${Header}>
<i>jsx-slack custom block</i> :sunglasses:
<//>
<Section>Let's build your block.</Section>
</Blocks>
`)
Please notice to a usage of component that has a bit different syntax from JSX.
💡 TIPS:
jsxslack
tag will return JSX element, or JSON if the root element was serializable. You can usejsxslack.raw
instead if you always want the raw JSX element.
- slack-jsx - Compose Slack messages from JSX Components instead of writing JSON.
- react-chat-renderer - React renderer implementation for building rich Slack messages using JSX.
Managed by Speee, Inc. (@speee)
- Yuki Hattori (@yhatt) - Maintainer