# Adding An Emoji Picker

We can use the [willRenderShapePresetToolbar](../../api/markup-editor/properties/#willrendershapepresettoolbar) hook to add custom shape preset tools to the sticker and preset toolbars.

In the example below we use [emoji-picker-element](https://github.com/nolanlawson/emoji-picker-element) to add an Emoji picker to the preset tab of the annotation util. We can see an example of this control on [Edit • Photo](https://edit.photo/)

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-0)

* [index.html](#index-html-panel-0)

```html
<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor, createNode, appendNode } from './pintura.js';

    const addSmiley = (editor, addPreset, smiley) => {
        // update the recent smileys
        const recent = new Set([smiley, ...editor.annotatePresets]);
        const recentArr = Array.from(recent);

        // max of five
        if (recentArr.length > 5) recentArr.length = 5;
        editor.annotatePresets = recentArr;

        // add the smiley to the canvas
        addPreset(smiley);
    };

    let picker = undefined;

    let imported = false;

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',
        util: 'annotate',
        willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
            // import from unpkg
            if (!imported) {
                import('https://unpkg.com/emoji-picker-element')
                    .then(() => {
                        imported = true;
                        redraw();
                    })
                    // silently error out
                    .catch(console.log);
                return toolbar;
            }

            // create root
            if (!picker) {
                // create the picker
                const emojiPicker = document.createElement('emoji-picker');

                // enable touch scroll of Pintura child element on iOS
                emojiPicker.dataset.touchScroll = 'true';

                // exit if no shadow root
                if (!emojiPicker.shadowRoot) return toolbar;

                // set custom styles to make it fit better
                const style = document.createElement('style');
                style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
                emojiPicker.shadowRoot.appendChild(style);

                // set theme, light or dark
                emojiPicker.className = 'light';

                // handle picking an emoji
                emojiPicker.addEventListener('emoji-click', (e) =>
                    addSmiley(editor, addPreset, e.detail.unicode)
                );
                picker = emojiPicker;
            }

            // append the picker Panel
            appendNode(
                createNode('Panel', 'emoji', {
                    buttonLabel: 'Emoji',
                    root: picker,
                }),
                toolbar
            );

            return toolbar;
        },
    });
</script>

```

* [App.jsx](#App-jsx-panel-0)
* [App.css](#App-css-panel-0)

```jsx
import '@pqina/pintura/pintura.css';
import './App.css';
import { useRef, useState } from 'react';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';

const editorDefaults = getEditorDefaults();

const addSmiley = (editor, addPreset, smiley) => {
    // update the recent smileys
    const recent = new Set([smiley, ...editor.annotatePresets]);
    const recentArr = Array.from(recent);

    // max of five
    if (recentArr.length > 5) recentArr.length = 5;
    editor.annotatePresets = recentArr;

    // add the smiley to the canvas
    addPreset(smiley);
};

function App() {
    const [picker, setPicker] = useState(undefined);

    const [imported, setImported] = useState(false);

    const editorRef = useRef(null);

    const willRenderShapePresetToolbar = (toolbar, addPreset, env, redraw) => {
        // import from unpkg
        if (!imported) {
            import('https://unpkg.com/emoji-picker-element')
                .then(() => {
                    setImported(true);
                    redraw();
                })
                // silently error out
                .catch(console.log);
            return toolbar;
        }

        // create root
        if (!picker) {
            // create the picker
            const emojiPicker = document.createElement('emoji-picker');

            // enable touch scroll of Pintura child element on iOS
            emojiPicker.dataset.touchScroll = 'true';

            // exit if no shadow root
            if (!emojiPicker.shadowRoot) return toolbar;

            // set custom styles to make it fit better
            const style = document.createElement('style');
            style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
            emojiPicker.shadowRoot.appendChild(style);

            // set theme, light or dark
            emojiPicker.className = 'light';

            // handle picking an emoji
            emojiPicker.addEventListener('emoji-click', (e) =>
                addSmiley(editorRef.current.editor, addPreset, e.detail.unicode)
            );
            setPicker(emojiPicker);
        }

        // append the picker Panel
        appendNode(
            createNode('Panel', 'emoji', {
                buttonLabel: 'Emoji',
                root: picker,
            }),
            toolbar
        );

        return toolbar;
    };

    return (
        <div className="App">
            <PinturaEditor
                ref={editorRef}
                {...editorDefaults}
                src={'image.jpeg'}
                util={'annotate'}
                willRenderShapePresetToolbar={willRenderShapePresetToolbar}
            />
        </div>
    );
}

export default App;

```

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-0)

```html
<template>
    <div>
        <PinturaEditor
            ref="editor"
            v-bind="editorDefaults"
            src="image.jpeg"
            util="annotate"
            :willRenderShapePresetToolbar="willRenderShapePresetToolbar"
        />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';

const addSmiley = function (editor, addPreset, smiley) {
    // update the recent smileys
    const recent = new Set([smiley, ...editor.annotatePresets]);
    const recentArr = Array.from(recent);

    // max of five
    if (recentArr.length > 5) recentArr.length = 5;
    editor.annotatePresets = recentArr;

    // add the smiley to the canvas
    addPreset(smiley);
};

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults(),

            picker: undefined,

            imported: false,

            willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
                // import from unpkg
                if (!this.imported) {
                    import('https://unpkg.com/emoji-picker-element')
                        .then(() => {
                            this.imported = true;
                            redraw();
                        })
                        // silently error out
                        .catch(console.log);
                    return toolbar;
                }

                // create root
                if (!this.picker) {
                    // create the picker
                    const emojiPicker = document.createElement('emoji-picker');

                    // enable touch scroll of Pintura child element on iOS
                    emojiPicker.dataset.touchScroll = 'true';

                    // exit if no shadow root
                    if (!emojiPicker.shadowRoot) return toolbar;

                    // set custom styles to make it fit better
                    const style = document.createElement('style');
                    style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
                    emojiPicker.shadowRoot.appendChild(style);

                    // set theme, light or dark
                    emojiPicker.className = 'light';

                    // handle picking an emoji
                    emojiPicker.addEventListener('emoji-click', (e) =>
                        addSmiley(
                            this.$refs.editor.editor,
                            addPreset,
                            e.detail.unicode
                        )
                    );

                    this.picker = emojiPicker;
                }

                // append the picker Panel
                appendNode(
                    createNode('Panel', 'emoji', {
                        buttonLabel: 'Emoji',
                        root: this.picker,
                    }),
                    toolbar
                );

                return toolbar;
            },
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

.pintura-editor {
    height: 600px;
}
</style>

```

* [App.svelte](#App-svelte-panel-0)

```svelte
<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults, createNode, appendNode } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    const addSmiley = (editor, addPreset, smiley) => {
        // update the recent smileys
        const recent = new Set([smiley, ...editor.annotatePresets]);
        const recentArr = Array.from(recent);

        // max of five
        if (recentArr.length > 5) recentArr.length = 5;
        editor.annotatePresets = recentArr;

        // add the smiley to the canvas
        addPreset(smiley);
    };

    let editorDefaults = getEditorDefaults();

    let picker = undefined;

    let imported = false;

    let editor;

    const willRenderShapePresetToolbar = (toolbar, addPreset, env, redraw) => {
        // import from unpkg
        if (!imported) {
            import('https://unpkg.com/emoji-picker-element')
                .then(() => {
                    imported = true;
                    redraw();
                })
                // silently error out
                .catch(console.log);
            return toolbar;
        }

        // create root
        if (!picker) {
            // create the picker
            const emojiPicker = document.createElement('emoji-picker');

            // enable touch scroll of Pintura child element on iOS
            emojiPicker.dataset.touchScroll = 'true';

            // exit if no shadow root
            if (!emojiPicker.shadowRoot) return toolbar;

            // set custom styles to make it fit better
            const style = document.createElement('style');
            style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
            emojiPicker.shadowRoot.appendChild(style);

            // set theme, light or dark
            emojiPicker.className = 'light';

            // handle picking an emoji
            emojiPicker.addEventListener('emoji-click', (e) =>
                addSmiley(editor, addPreset, e.detail.unicode)
            );

            picker = emojiPicker;
        }

        // append the picker Panel
        appendNode(
            createNode('Panel', 'emoji', {
                buttonLabel: 'Emoji',
                root: picker,
            }),
            toolbar
        );

        return toolbar;
    };
</script>

<div>
    <PinturaEditor
        bind:this={editor}
        {...editorDefaults}
        src={'image.jpeg'}
        util={'annotate'}
        {willRenderShapePresetToolbar}
    />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>

```

* [app.component.ts](#app-component-ts-panel-0)
* [app.component.html](#app-component-html-panel-0)
* [app.component.css](#app-component-css-panel-0)
* [app.module.ts](#app-module-ts-panel-0)

```javascript
import { Component, ViewChild } from '@angular/core';

import {
    getEditorDefaults,
    createNode,
    appendNode,
    PinturaNode,
    Sticker,
} from '@pqina/pintura';

const addSmiley = (
    editor: any,
    addPreset: (preset: Sticker) => void,
    smiley: string
): void => {
    // update the recent smileys
    const recent = new Set([smiley, ...editor.annotatePresets]);
    const recentArr = Array.from(recent);

    // max of five
    if (recentArr.length > 5) recentArr.length = 5;
    editor.annotatePresets = recentArr;

    // add the smiley to the canvas
    addPreset(smiley);
};

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    @ViewChild('editor') editor?: any;

    editorDefaults: any = getEditorDefaults();

    picker: HTMLElement | undefined = undefined;

    imported: Boolean = false;

    willRenderShapePresetToolbar = (
        toolbar: PinturaNode[],
        addPreset: (preset: Sticker) => void,
        env: any,
        redraw: () => void
    ): PinturaNode[] => {
        // import from unpkg
        if (!this.imported) {
            import('emoji-picker-element')
                .then(() => {
                    this.imported = true;
                    redraw();
                })
                // silently error out
                .catch(console.log);
            return toolbar;
        }

        // create root
        if (!this.picker) {
            // create the picker
            const emojiPicker = document.createElement('emoji-picker');

            // enable touch scroll of Pintura child element on iOS
            emojiPicker.dataset.touchScroll = 'true';

            // exit if no shadow root
            if (!emojiPicker.shadowRoot) return toolbar;

            // set custom styles to make it fit better
            const style = document.createElement('style');
            style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
            emojiPicker.shadowRoot.appendChild(style);

            // set theme, light or dark
            emojiPicker.className = 'light';

            // handle picking an emoji
            emojiPicker.addEventListener('emoji-click', (e) =>
                addSmiley(this.editor.editor, addPreset, e.detail.unicode)
            );

            this.picker = emojiPicker;
        }

        // append the picker Panel
        appendNode(
            createNode('Panel', 'emoji', {
                buttonLabel: 'Emoji',
                root: this.picker,
            }),
            toolbar
        );

        return toolbar;
    };
}

```

```html
<pintura-editor
    #editor
    [options]="editorDefaults"
    src="image.jpeg"
    util="annotate"
    [willRenderShapePresetToolbar]="willRenderShapePresetToolbar"
></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-0)

```html
<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var { createNode, appendNode } = $.fn.pintura;

        const addSmiley = (editor, addPreset, smiley) => {
            // update the recent smileys
            const recent = new Set([smiley, ...editor.annotatePresets]);
            const recentArr = Array.from(recent);

            // max of five
            if (recentArr.length > 5) recentArr.length = 5;
            editor.annotatePresets = recentArr;

            // add the smiley to the canvas
            addPreset(smiley);
        };

        var picker = undefined;

        var imported = false;

        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',
            util: 'annotate',
            willRenderShapePresetToolbar: (toolbar, addPreset, env, redraw) => {
                // import from unpkg
                if (!imported) {
                    import('https://unpkg.com/emoji-picker-element')
                        .then(() => {
                            imported = true;
                            redraw();
                        })
                        // silently error out
                        .catch(console.log);
                    return toolbar;
                }

                // create root
                if (!picker) {
                    // create the picker
                    const emojiPicker = document.createElement('emoji-picker');

                    // enable touch scroll of Pintura child element on iOS
                    emojiPicker.dataset.touchScroll = 'true';

                    // exit if no shadow root
                    if (!emojiPicker.shadowRoot) return toolbar;

                    // set custom styles to make it fit better
                    const style = document.createElement('style');
                    style.textContent = `
                                .favorites { display: none }
                                .emoji { border-radius: 0 }
                                button.emoji { border-radius: 0 }
                                .tabpanel {
                                    scrollbar-color:#ddd transparent;
                                    scrollbar-width: thin;
                                }
                                .tabpanel::-webkit-scrollbar {
                                    width: 1rem;
                                    cursor: pointer;
                                }
                                .tabpanel::-webkit-scrollbar-track {
                                    background: none;
                                }
                                .tabpanel::-webkit-scrollbar-thumb {
                                    cursor: pointer;
                                    background-clip: padding-box;
                                    background-color: #ddd;
                                    border-radius: 9999rem;
                                    border: 0.3125rem solid rgba(0, 0, 0, 0);
                                }
                            `;
                    emojiPicker.shadowRoot.appendChild(style);

                    // set theme, light or dark
                    emojiPicker.className = 'light';

                    // handle picking an emoji
                    emojiPicker.addEventListener('emoji-click', (e) =>
                        addSmiley(editor, addPreset, e.detail.unicode)
                    );
                    picker = emojiPicker;
                }

                // append the picker Panel
                appendNode(
                    createNode('Panel', 'emoji', {
                        buttonLabel: 'Emoji',
                        root: picker,
                    }),
                    toolbar
                );

                return toolbar;
            },
        });
    });
</script>

```