You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While each type of block can have its own set of properties, there are some properties that all built-in block types have by default, which you can find in the definition for `DefaultProps`:
@@ -144,98 +162,112 @@ type DefaultProps = {
144
162
145
163
## Custom Block Types
146
164
147
-
In addition to the default block types that BlockNote offers, you can also make your own custom blocks. Take a look at the demo below, in which we add a custom block containing an image and caption to a BlockNote editor, as well as a custom [Slash Menu Item](/docs/slash-menu#custom-items) to insert it.
165
+
In addition to the default block types that BlockNote offers, you can also make your own custom blocks. Take a look at the demo below, in which we add a custom block containing a paragraph with a different font to a BlockNote editor, as well as a custom [Slash Menu Item](/docs/slash-menu#custom-items) to insert it.
Let's look at our custom image block from the demo, and go over each field in-depth to explain how it works:
293
340
294
341
```typescript jsx
295
-
const ImageBlock =createReactBlockSpec({
296
-
type: "image",
297
-
propSchema: {
298
-
src: {
299
-
default: "https://via.placeholder.com/1000",
342
+
const FontparagraphBlock =createReactBlockSpec(
343
+
{
344
+
type: "fontParagraph",
345
+
propSchema: {
346
+
...defaultProps,
347
+
font: {
348
+
default: "Comic Sans MS",
349
+
},
300
350
},
351
+
content: "inline",
301
352
},
302
-
content: "inline",
303
-
render: ({ block }) => (
304
-
<div
305
-
style={{
306
-
display: "flex",
307
-
flexDirection: "column",
308
-
}}>
309
-
<img
310
-
style={{
311
-
width: "100%",
312
-
}}
313
-
src={block.props.src}
314
-
alt={"Image"}
315
-
contentEditable={false}
316
-
/>
317
-
<InlineContent/>
318
-
</div>
319
-
),
320
-
});
353
+
{
354
+
render: ({ block, contentRef }) => {
355
+
const style = {
356
+
fontFamily: block.props.font
357
+
};
358
+
359
+
return (
360
+
<pref={contentRef} style={style} />
361
+
);
362
+
},
363
+
parse: (element) => {
364
+
const font =element.style.fontFamily;
365
+
return {
366
+
font: font||undefined,
367
+
};
368
+
},
369
+
}
370
+
);
321
371
```
322
372
323
-
#### `type`
373
+
You can see that `createReactBlockSpec` takes two object arguments:
374
+
375
+
#### `blockConfig`
376
+
377
+
This defines the block's type, properties, and content type. It allows BlockNote to know how to handle manipulating the block internally and provide typing.
378
+
379
+
**`type`**
324
380
325
381
Defines the name of the block, in this case, `image`.
326
382
327
-
#### `propSchema`
383
+
**`content`**
384
+
385
+
As we saw in [Block Objects](/docs/blocks#block-objects), blocks can contain editable rich text which is represented as [Inline Content](/docs/inline-content). The `content` field allows your custom block to contain an editable rich-text field. Since we want to be able to type in our paragraph, we set it to `"inline"`.
328
386
329
-
This is an object which defines the props that the block should have. In this case, we want the block to have a `src` prop for the URL of the image, so we add a `src` key. We also want basic styling options for the image block, so we also add the [Default Block Properties](/docs/block-types#default-block-properties) using `defaultProps`. The value of each key is an object with a mandatory `default` field and an optional `values` field:
387
+
**`propSchema`**
330
388
331
-
`default:` Stores the prop's default value, so we use a placeholder image URL for `src` if no URL is provided.
389
+
This is an object which defines the props that the block should have. In this case, we want the block to have a `font` prop for the font that we want the paragraph to use, so we add a `font` key. We also want basic styling options, so we add the [Default Block Properties](/docs/block-types#default-block-properties) using `defaultProps`. The value of each key is an object with a mandatory `default` field and an optional `values` field:
332
390
333
-
`values:` Stores an array of strings that the prop can take. If `values` is not defined, BlockNote assumes the prop can be any string, which makes sense for `src`, since it can be any image URL.
391
+
`default:` Stores the prop's default value, in this case the Comic Sans MS font.
334
392
335
-
#### `containsInlineContent`
393
+
`values:` Stores an array of strings that the prop can take. If `values` is not defined, BlockNote assumes the prop can be any string, which makes sense for `font`, since we don't want to list every possible font name.
336
394
337
-
As we saw in [Block Objects](/docs/blocks#block-objects), blocks can contain editable rich text which is represented as [Inline Content](/docs/inline-content). The `containsInlineContent` field allows your custom block to contain an editable rich-text field. For the custom image block, we use an inline content field to create our caption, so it's set to `true`.
395
+
#### `blockImplementation`
338
396
339
-
#### `render`
397
+
This defines how the block should be rendered in the editor, and how it should be parsed from and converted to HTML.
340
398
341
-
This is a React component which defines how your custom block should be rendered in the editor, and takes two props:
399
+
**`render`**
342
400
343
-
`block:` The block that should be rendered.
401
+
This is a React component which defines how your custom block should be rendered in the editor, and takes three props:
402
+
403
+
`block:` The block that should be rendered. This will always have the same type, props, and content as defined in the block's config.
344
404
345
405
`editor:` The BlockNote editor instance that the block is in.
346
406
347
-
For our custom image block, we use a parent `div` which contains the image and caption. Since `block` will always be an `image` block, we also know it contains a `src` prop, and can pass it to the child `img` element.
407
+
`contentRef:` A React `ref` that marks which element in your block is editable, This is only useful if your block config contains `content: "inline"`.
408
+
409
+
**`toExternalHTML`**
410
+
411
+
This is identical in definition as `render`, but is used whenever the block is being exported to HTML for use outside BlockNote, namely when copying it to the clipboard. If it's not defined, BlockNote will just use `render` for the HTML conversion.
348
412
349
-
But what's this `InlineContent` component? Since we set `containsInlineContent` to `true`, it means we want to include an editable rich-text field somewhere in the image block. You should use the `InlineContent` component to represent this field in your `render` component. Since we're using it to create our caption, we add it below the `img` element.
413
+
**`parse`**
350
414
351
-
In the DOM, the `InlineContent` component is rendered as a `div` by default, but you can make it use a different element by passing `as={"elementTag"}` as a prop. For example, `as={"p"}` will make the `InlineContent` component get rendered to a paragraph.
415
+
This is a function that allows you to define which HTML elements should be parsed into your block when importing HTML from outside BlockNote, namely when pasting it from the clipboard. If the element should be parsed into your custom block, you should return the props that the block should be given. Otherwise, return `undefined`.
352
416
353
-
While the `InlineContent` component can be put anywhere inside the component you pass to `render`, you should make sure to only have one. If `containsInlineContent` is set to false, `render` shouldn't contain any.
417
+
`element`: The HTML element that's being parsed.
354
418
355
419
### Adding Custom Blocks to the Editor
356
420
357
-
Now, we need to tell BlockNote to use our custom image block by passing it to the editor in the `blockSchema` option. Let's again look at the image block from the demo as an example:
421
+
Now, we need to tell BlockNote to use our font paragraph block by passing it to the editor in the `blockSpecs` option. Let's again look at the image block from the demo as an example:
358
422
359
423
```typescript jsx
424
+
// Our block specs, which contain the configs and implementations for blocks
425
+
// that we want our editor to use.
426
+
const blockSpecs = {
427
+
// Adds all default blocks.
428
+
...defaultBlockSpecs,
429
+
// Adds the font paragraph.
430
+
fontParagraph: FontParagraphBlock,
431
+
};
432
+
433
+
...
434
+
360
435
// Creates a new editor instance.
361
436
const editor =useBlockNote({
362
437
// Tells BlockNote which blocks to use.
363
-
blockSchema: {
364
-
// Adds all default blocks.
365
-
...defaultBlockSchema,
366
-
// Adds the custom image block.
367
-
image: ImageBlock,
368
-
},
438
+
blockSpecs: blockSpecs,
369
439
});
370
440
```
371
441
372
-
Since we still want the editor to use the [Built-In Block Types](/docs/block-types#built-in-block-types), we add `defaultBlockSchema` to our custom block schema. The key which we use for the custom image block is the same string we use for its type. Make sure that this is always the case for your own custom blocks.
442
+
Since we still want the editor to use the [Built-In Block Types](/docs/block-types#built-in-block-types), we add `defaultBlockSpecs` too. The key which we use for the font paragraph block should also be the same string we use for its type. Make sure that this is always the case for your own custom blocks.
373
443
374
444
And we're done! You now know how to create custom blocks and add them to the editor. Head to [Manipulating Blocks](/docs/manipulating-blocks) to see what you can do with them in the editor.
0 commit comments