Every layout, sizing and locale prop, wired to live controls so you can see what each one does.

Configuration

Every layout, sizing and locale prop, wired to live controls so you can see what each one does.


Overview

The picker's shape is entirely prop-driven. The demo below wires every layout prop to a control so you can dial in the configuration you want and copy the resulting call.

Live demo

Sizing

PropDefaultWhat it does
perLine9Emojis per row. Also sets the picker's width unless dynamicWidth is on.
emojiSize24Size of the glyph, in px.
emojiButtonSize36Size of the button around the glyph, in px.
emojiButtonRadius"100%"Any CSS radius — "6px" gives square-ish buttons.
dynamicWidthFalseLet the picker fill its container instead of sizing from perLine.

With dynamicWidth=True the picker measures its parent, so perLine stops having a visible effect. Put it in a fixed-width parent, or leave dynamicWidth off.

Layout

PropDefaultOptions
navPosition"top""top", "bottom", "none"
previewPosition"bottom""top", "bottom", "none"
searchPosition"sticky""sticky", "static", "none"
skinTonePosition"preview""preview", "search", "none"
maxFrequentRows40 hides the "frequently used" category entirely.

Content

categories picks which built-in categories appear, and in what order. Leaving it empty (the default) shows all of them:

DashEmojiMart(
    id="picker",
    categories=["frequent", "people", "nature", "foods"],
    exceptEmojis=["rage", "cry"],
    noCountryFlags=True,
)

The built-in category ids are frequent, people, nature, foods, activity, places, objects, symbols and flags.

Do not list custom category ids here, and do not pass this prop at all when you pass custom. emoji-mart filters it against a category list it snapshots on the first picker initialised in the page's lifetime, so custom ids resolve on that first picker and are silently dropped on every one after it. See Custom emojis for the full mechanism.

Emoji set and locale

set chooses which artwork the picker renders: "native" (the default — the OS's own emoji font, no images fetched), or "apple", "google", "twitter", "facebook", which load spritesheets from jsDelivr.

locale translates the UI and search index. "en", "ar", "be", "cs", "de", "es", "fa", "fi", "fr", "hi", "it", "ja", "ko", "nl", "pl", "pt", "ru", "sa", "tr", "uk", "vi" and "zh" ship with emoji-mart.

Two controls above can take a category away and not give it back:

setting it back to 4 does not bring it back;

Both are the same emoji-mart behaviour, and it is global rather than per-picker. init() builds Data.categories once and then mutates that array in place: a category that ends up empty is spliced straight out of it. The only code path that rebuilds the list from Data.originalCategories is the one that runs when you pass categories — which is why choosing categories restores Frequently-used while clearing them does not.

So the state lives in a module global that outlives the component, the page and every remount. Reloading the page is the only reset. If a category needs to come and go at runtime, pass categories explicitly every time rather than relying on the empty default.

Turn noCountryFlags on above, then type "united" into the picker's search box. The flags category has shrunk to a short safe list — and the search still returns the flags of the UK, the US, the UAE and the UN.

Measured against emoji-mart 5.6.0, and it is the same code path for both props: the filter runs while each category is built and splices the emoji out of category.emojis, while SearchIndex.search matches over Object.values(Data.emojis) — the unfiltered map — and applies no category filter of its own.

Not worked around in this component, deliberately. emoji-mart loads its data into a module-global exactly once per page, so pre-filtering the data for one picker would silently change every other picker on the page, and every page after it in a Dash SPA — the same aliasing trap described on Custom emojis. A visible search result beats an invisible, mount-order-dependent one.

Use them for tidying, never as access control. To keep an emoji away from a user entirely, pass a trimmed data set rather than a filter.

emoji-mart reads both once, when it initialises its internal store. Updating either prop on a live picker leaves the old data in place. Wrap the picker in a html.Div(..., id=...) whose id varies with the value, as the demo above does — Dash keys every child on its id, so a new id means React discards the old picker instead of patching it.

Not key=. Dash's html components accept a key prop, but the renderer never reads it when reconciling: it builds the React key from the component's id (key: container.props.id ? stringifyId(container.props.id) : stringifyPath(path)). A key= therefore forces no remount and reaches the <div> as a stray prop, which is the source of the ` key is not a prop ` warning in the console.

Source

# File: docs/configuration/example.py

"""Every layout prop bound to a live control, plus the generated call.

Note the varying `id=` on the wrapper Div. emoji-mart reads `set` and `locale` once when
it builds its internal store, so changing either on a mounted picker does nothing
visible; the picker has to be unmounted and remounted for the data to reload.

The id is what triggers that. Dash's renderer keys each child on its id —
`key: container.props.id ? stringifyId(container.props.id) : stringifyPath(path)` in
DashWrapper — so a different wrapper id is a different React key, and React discards the
old subtree instead of patching it. A `key=` prop does NOT do this: html components
accept it, but the renderer never reads it for reconciliation, so it only reaches the
`<div>` as a stray prop and React warns "`key` is not a prop".
"""

import dash_mantine_components as dmc
from dash import Input, Output, callback, html

from dash_emoji_mart import DashEmojiMart

CATEGORY_OPTIONS = [
    {"value": "frequent", "label": "Frequently used"},
    {"value": "people", "label": "People"},
    {"value": "nature", "label": "Nature"},
    {"value": "foods", "label": "Food & drink"},
    {"value": "activity", "label": "Activities"},
    {"value": "places", "label": "Travel & places"},
    {"value": "objects", "label": "Objects"},
    {"value": "symbols", "label": "Symbols"},
    {"value": "flags", "label": "Flags"},
]


def _select(component_id, label, options, value):
    return dmc.Select(
        id=component_id,
        label=label,
        data=[{"value": v, "label": lbl} for v, lbl in options],
        value=value,
        allowDeselect=False,
    )


controls = dmc.Stack(
    [
        dmc.SimpleGrid(
            [
                dmc.NumberInput(
                    id="cfg-per-line", label="perLine", value=9, min=4, max=16
                ),
                dmc.NumberInput(
                    id="cfg-emoji-size", label="emojiSize", value=24, min=14, max=48, step=2
                ),
                dmc.NumberInput(
                    id="cfg-button-size",
                    label="emojiButtonSize",
                    value=36,
                    min=22,
                    max=64,
                    step=2,
                ),
                dmc.NumberInput(
                    id="cfg-max-frequent", label="maxFrequentRows", value=4, min=0, max=8
                ),
            ],
            cols={"base": 2, "md": 4},
            spacing="md",
        ),
        dmc.SimpleGrid(
            [
                _select(
                    "cfg-nav",
                    "navPosition",
                    [("top", "top"), ("bottom", "bottom"), ("none", "none")],
                    "top",
                ),
                _select(
                    "cfg-preview",
                    "previewPosition",
                    [("top", "top"), ("bottom", "bottom"), ("none", "none")],
                    "bottom",
                ),
                _select(
                    "cfg-search",
                    "searchPosition",
                    [("sticky", "sticky"), ("static", "static"), ("none", "none")],
                    "sticky",
                ),
                _select(
                    "cfg-skin-tone",
                    "skinTonePosition",
                    [("preview", "preview"), ("search", "search"), ("none", "none")],
                    "preview",
                ),
            ],
            cols={"base": 2, "md": 4},
            spacing="md",
        ),
        dmc.SimpleGrid(
            [
                _select(
                    "cfg-set",
                    "set",
                    [
                        ("native", "native"),
                        ("apple", "apple"),
                        ("google", "google"),
                        ("twitter", "twitter"),
                        ("facebook", "facebook"),
                    ],
                    "native",
                ),
                _select(
                    "cfg-locale",
                    "locale",
                    [
                        ("en", "English"),
                        ("es", "Español"),
                        ("fr", "Français"),
                        ("de", "Deutsch"),
                        ("ja", "日本語"),
                        ("zh", "中文"),
                    ],
                    "en",
                ),
                dmc.NumberInput(id="cfg-skin", label="skin", value=1, min=1, max=6),
                dmc.TextInput(
                    id="cfg-radius", label="emojiButtonRadius", value="100%"
                ),
            ],
            cols={"base": 2, "md": 4},
            spacing="md",
        ),
        dmc.MultiSelect(
            id="cfg-categories",
            label="categories (empty shows all)",
            data=CATEGORY_OPTIONS,
            value=[],
            clearable=True,
        ),
        dmc.Group(
            [
                dmc.Switch(id="cfg-dynamic-width", label="dynamicWidth", checked=False),
                dmc.Switch(id="cfg-auto-focus", label="autoFocus", checked=False),
                dmc.Switch(id="cfg-no-flags", label="noCountryFlags", checked=False),
            ],
            gap="xl",
        ),
    ],
    gap="md",
)

component = dmc.Stack(
    [
        dmc.Paper(controls, withBorder=True, p="lg", radius="md"),
        dmc.Group(
            [
                # `flex: 1` and `minWidth: 0` are what make `dynamicWidth`
                # demonstrable rather than broken.
                #
                # dynamicWidth tells emoji-mart to set `width: 100%` instead of
                # sizing itself from `perLine`. A bare Div inside this flex
                # Group is `flex: 0 1 auto`, so its own width comes from its
                # content — and the content is now asking for 100% OF THAT.
                # The circular constraint resolves at min-content, so turning
                # the switch on made the picker COLLAPSE from 352px to 190px
                # and the grid reflow under the pointer, which reads as the
                # component glitching.
                #
                # Giving the mount a real width to fill fixes it: `flex: 1`
                # makes it claim the leftover row space, `minWidth: 0` lets it
                # shrink below its content's intrinsic width instead of forcing
                # the Group wider.
                html.Div(id="cfg-picker", style={"flex": 1, "minWidth": 0}),
                dmc.Stack(
                    [
                        dmc.Paper(
                            [
                                dmc.Text("Selected", size="sm", c="dimmed"),
                                html.Div(
                                    id="cfg-output",
                                    style={"fontSize": 48, "minHeight": 60},
                                ),
                            ],
                            withBorder=True,
                            p="lg",
                            radius="md",
                            style={"minWidth": 200, "textAlign": "center"},
                        ),
                        dmc.CodeHighlight(
                            id="cfg-code", code="", language="python"
                        ),
                    ],
                    gap="md",
                    style={"flex": 1, "minWidth": 300},
                ),
            ],
            align="flex-start",
            gap="xl",
        ),
    ],
    gap="md",
)


@callback(
    Output("cfg-picker", "children"),
    Output("cfg-code", "code"),
    Input("cfg-per-line", "value"),
    Input("cfg-emoji-size", "value"),
    Input("cfg-button-size", "value"),
    Input("cfg-max-frequent", "value"),
    Input("cfg-nav", "value"),
    Input("cfg-preview", "value"),
    Input("cfg-search", "value"),
    Input("cfg-skin-tone", "value"),
    Input("cfg-set", "value"),
    Input("cfg-locale", "value"),
    Input("cfg-skin", "value"),
    Input("cfg-radius", "value"),
    Input("cfg-categories", "value"),
    Input("cfg-dynamic-width", "checked"),
    Input("cfg-auto-focus", "checked"),
    Input("cfg-no-flags", "checked"),
)
def rebuild(
    per_line,
    emoji_size,
    button_size,
    max_frequent,
    nav,
    preview,
    search,
    skin_tone,
    emoji_set,
    locale,
    skin,
    radius,
    categories,
    dynamic_width,
    auto_focus,
    no_flags,
):
    props = {
        "perLine": per_line if per_line is not None else 9,
        "emojiSize": emoji_size if emoji_size is not None else 24,
        "emojiButtonSize": button_size if button_size is not None else 36,
        "emojiButtonRadius": radius or "100%",
        "maxFrequentRows": max_frequent if max_frequent is not None else 4,
        "navPosition": nav or "top",
        "previewPosition": preview or "bottom",
        "searchPosition": search or "sticky",
        "skinTonePosition": skin_tone or "preview",
        "set": emoji_set or "native",
        "locale": locale or "en",
        "skin": skin if skin is not None else 1,
        "dynamicWidth": bool(dynamic_width),
        "autoFocus": bool(auto_focus),
        "noCountryFlags": bool(no_flags),
    }
    if categories:
        props["categories"] = categories

    rendered = ",\n".join(f"    {k}={v!r}" for k, v in props.items())
    code = f'DashEmojiMart(\n    id="picker",\n{rendered},\n)'

    # `set` and `locale` only take effect on a fresh mount, so they go in the wrapper id
    # — that is what Dash turns into the React key. See the module docstring.
    mount_id = f"cfg-mount-{props['set']}-{props['locale']}"
    return html.Div(DashEmojiMart(id="cfg-emoji-picker", **props), id=mount_id), code


@callback(Output("cfg-output", "children"), Input("cfg-emoji-picker", "value"))
def show(value):
    if not value:
        return dmc.Text("Nothing yet", c="dimmed", size="lg")
    if value.startswith("http"):
        return html.Img(src=value, style={"width": 48, "height": 48})
    return value

Source: /configuration

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: