Skip to content

Create a Custom Block

This example creates a “sticker” block—a large emoji that can be placed, rotated, and resized on the canvas. It includes a custom toolbar button and a floating menu emoji picker.

<script setup lang="ts">
import { WovenCanvas, SelectTool, HandTool, FloatingMenuBar, Toolbar } from '@woven-canvas/vue'
import '@woven-canvas/vue/style.css'
import { Sticker } from './Sticker'
import StickerBlock from './StickerBlock.vue'
import StickerTool from './StickerTool.vue'
import StickerMenuButton from './StickerMenuButton.vue'
const blockDefs = [
{
tag: 'sticker',
components: [Sticker],
},
]
</script>
<template>
<WovenCanvas :editor="{ components: [Sticker], blockDefs }">
<!-- Toolbar -->
<template #toolbar>
<Toolbar>
<SelectTool />
<HandTool />
<StickerTool />
</Toolbar>
</template>
<!-- Floating menu with emoji picker -->
<template #floating-menu>
<FloatingMenuBar>
<template #button:sticker="{ entityIds }">
<StickerMenuButton :entity-ids="entityIds" />
</template>
</FloatingMenuBar>
</template>
<!-- Block renderer -->
<template #block:sticker="props">
<StickerBlock v-bind="props" />
</template>
</WovenCanvas>
</template>

Defines a canvas component to store the sticker’s emoji. The name: "sticker" is used for slot naming (#block:sticker, #button:sticker).

Renders the emoji using useComponent() to reactively read the sticker data. Uses CSS container queries to scale the emoji with the block size.

Registers the block type with tag and components. The #block:sticker slot renders StickerBlock for any block with tag: "sticker".

Creates a toolbar button using ToolbarButton. The placement-snapshot defines what gets created when the tool is used—a block with tag: "sticker" and initial emoji data.

Adds an emoji picker to the floating menu using MenuButton and MenuDropdown. Uses useComponents() to read data from all selected stickers, and nextEditorTick() to write changes.

The slot #button:sticker only appears when all selected blocks have the Sticker component.