Alert Block
In this example, we create a custom Alert block which is used to emphasize text.
Try it out: Click the "!" icon to change the alert type!
Relevant Docs:
import { defaultProps } from "@blocknote/core";import { createReactBlockSpec } from "@blocknote/react";import { Menu } from "@mantine/core";import { MdCancel, MdCheckCircle, MdError, MdInfo } from "react-icons/md";import "./styles.css";// The types of alerts that users can choose from.export const alertTypes = [ { title: "Warning", value: "warning", icon: MdError, color: "#e69819", backgroundColor: { light: "#fff6e6", dark: "#805d20", }, }, { title: "Error", value: "error", icon: MdCancel, color: "#d80d0d", backgroundColor: { light: "#ffe6e6", dark: "#802020", }, }, { title: "Info", value: "info", icon: MdInfo, color: "#507aff", backgroundColor: { light: "#e6ebff", dark: "#203380", }, }, { title: "Success", value: "success", icon: MdCheckCircle, color: "#0bc10b", backgroundColor: { light: "#e6ffe6", dark: "#208020", }, },] as const;// The Alert block.export const createAlert = createReactBlockSpec( { type: "alert", propSchema: { textAlignment: defaultProps.textAlignment, textColor: defaultProps.textColor, type: { default: "warning", values: ["warning", "error", "info", "success"], }, }, content: "inline", }, { render: (props) => { const alertType = alertTypes.find( (a) => a.value === props.block.props.type, )!; const Icon = alertType.icon; return ( <div className={"alert"} data-alert-type={props.block.props.type}> {/*Icon which opens a menu to choose the Alert type*/} <Menu withinPortal={false}> <Menu.Target> <div className={"alert-icon-wrapper"} contentEditable={false}> <Icon className={"alert-icon"} data-alert-icon-type={props.block.props.type} size={32} /> </div> </Menu.Target> {/*Dropdown to change the Alert type*/} <Menu.Dropdown> <Menu.Label>Alert Type</Menu.Label> <Menu.Divider /> {alertTypes.map((type) => { const ItemIcon = type.icon; return ( <Menu.Item key={type.value} leftSection={ <ItemIcon className={"alert-icon"} data-alert-icon-type={type.value} /> } onClick={() => props.editor.updateBlock(props.block, { type: "alert", props: { type: type.value }, }) } > {type.title} </Menu.Item> ); })} </Menu.Dropdown> </Menu> {/*Rich text field for user to type in*/} <div className={"inline-content"} ref={props.contentRef} /> </div> ); }, },);import { BlockNoteSchema, defaultBlockSpecs } from "@blocknote/core";import "@blocknote/core/fonts/inter.css";import { BlockNoteView } from "@blocknote/mantine";import "@blocknote/mantine/style.css";import { useCreateBlockNote } from "@blocknote/react";import { createAlert } from "./Alert";// Our schema with block specs, which contain the configs and implementations for// blocks that we want our editor to use.const schema = BlockNoteSchema.create().extend({ blockSpecs: { // Creates an instance of the Alert block and adds it to the schema. alert: createAlert(), },});export default function App() { // Creates a new editor instance. const editor = useCreateBlockNote({ schema, initialContent: [ { type: "paragraph", content: "Welcome to this demo!", }, { type: "alert", content: "This is an example alert", }, { type: "paragraph", content: "Click the '!' icon to change the alert type", }, { type: "paragraph", }, ], }); // Renders the editor instance. return <BlockNoteView editor={editor} />;}.alert { display: flex; justify-content: center; align-items: center; flex-grow: 1; border-radius: 4px; min-height: 48px; padding: 4px;}.alert[data-alert-type="warning"] { background-color: #fff6e6;}.alert[data-alert-type="error"] { background-color: #ffe6e6;}.alert[data-alert-type="info"] { background-color: #e6ebff;}.alert[data-alert-type="success"] { background-color: #e6ffe6;}[data-color-scheme="dark"] .alert[data-alert-type="warning"] { background-color: #805d20;}[data-color-scheme="dark"] .alert[data-alert-type="error"] { background-color: #802020;}[data-color-scheme="dark"] .alert[data-alert-type="info"] { background-color: #203380;}[data-color-scheme="dark"] .alert[data-alert-type="success"] { background-color: #208020;}.alert-icon-wrapper { border-radius: 16px; display: flex; justify-content: center; align-items: center; margin-left: 12px; margin-right: 12px; height: 18px; width: 18px; user-select: none; cursor: pointer;}.alert-icon[data-alert-icon-type="warning"] { color: #e69819;}.alert-icon[data-alert-icon-type="error"] { color: #d80d0d;}.alert-icon[data-alert-icon-type="info"] { color: #507aff;}.alert-icon[data-alert-icon-type="success"] { color: #0bc10b;}.inline-content { flex-grow: 1;}