• English
  • CharacterPicker

    Shape and ink chooser.

    Shape
    Colour
    import { useState } from 'react';
    import { CharacterPicker, CharacterMark, type FaceStyle } from '@aora-bot/react';
    
    export default function Demo() {
      const [shape, setShape] = useState('blob' as const);
      const [color, setColor] = useState('blue' as const);
    
      return (
        <div className="site-demo">
          <CharacterMark shape={shape} color={color} state="happy" sizePx={120} />
          <CharacterPicker
            shape={shape}
            color={color}
            onSelectShape={setShape as never}
            onSelectColor={setColor as never}
          />
        </div>
      );
    }

    The selection ring follows the shape

    The highlight is drawn in the selected shape's own outline, not as a generic circle — a hexagon gets a hexagonal ring. It is a CSS mask generated by the same function that draws the body, so a shape registered with defineShape gets a correct ring without any extra work.

    Layouts

    Shape
    Colour
    import { CharacterPicker } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <div className="site-demo site-demo--column">
          <CharacterPicker
            shape="hex"
            color="green"
            layout="row"
            shapes={['blob', 'hex', 'onigiri', 'cloud', 'leaf']}
          />
        </div>
      );
    }

    Face style and nose

    Pass face to add a cute | eyes | line toggle. While the line face is selected a row of the six noses follows, and every shape preview is drawn in the chosen style so the reader sees what they will get.

    Shape
    Colour
    Face
    Nose
    import { useState } from 'react';
    import { CharacterPicker, CharacterMark, type FaceStyle } from '@aora-bot/react';
    
    export default function Demo() {
      const [shape, setShape] = useState('pear' as const);
      const [color, setColor] = useState('green' as const);
      const [face, setFace] = useState<FaceStyle>('line');
      const [nose, setNose] = useState('slant' as const);
    
      return (
        <div className="site-demo">
          <CharacterMark shape={shape} color={color} state="happy" sizePx={120} face={face} nose={nose} />
          <CharacterPicker
            shape={shape}
            color={color}
            face={face}
            nose={nose}
            shapes={['pear', 'blob', 'bun', 'ghost', 'egg', 'tofu']}
            colors={['green', 'blue', 'orange']}
            onSelectShape={setShape as never}
            onSelectColor={setColor as never}
            onSelectFace={setFace}
            onSelectNose={setNose as never}
          />
        </div>
      );
    }

    Omit face and the picker stays a shape and ink chooser.

    Restricting the options

    Shape
    Colour
    import { CharacterPicker } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <CharacterPicker
          shape="pill"
          color="magenta"
          shapes={['pill', 'tofu', 'ghost', 'bell']}
          colors={['magenta', 'violet', 'cyan']}
        />
      );
    }

    Preview size

    sizePx sets the size of each shape preview; face and nose previews scale with it. The default is PICKER_MARK_PX (36). lineWeight is passed to the previews so a picker matches the character it edits.

    Shape
    Colour
    import { CharacterPicker } from '@aora-bot/react';
    
    export default function Demo() {
      return (
        <CharacterPicker
          shape="star"
          color="yellow"
          layout="row"
          sizePx={24}
          shapes={['star', 'hex', 'flower', 'flame', 'bell']}
          colors={['yellow', 'orange', 'red']}
        />
      );
    }

    onSelectColor

    The colour callback is onSelectColor, spelt like the color prop and the ColorId type it hands back.

    Two more pickers

    AgentCharacterPicker holds its edits until they are confirmed, for a dialog where a click is a proposal and Cancel has to mean something. CompactCharacterPicker is cut down to a handful of shapes and inks, for the space beside a sign-up form.

    Keyboard and assistive technology

    One radio group per row — shapes, inks, and when enabled face style and nose — each with an accessible name. Every option has role="radio" and aria-checked, and focus is visible. Tab moves between the groups and arrow keys move within one, which is what a radio group is expected to do.

    API

    PropTypeDefaultDescription
    color*"black" | "brown" | "red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "violet" | "magenta" | "pink" | "gray"——
    shape*"mochi" | "circle" | "blob" | "pebble" | "egg" | "bun" | "tofu" | "pill" | "hex" | "onigiri" | "gem" | "cloud" | "drop" | "leaf" | "flower" | "clover" | "sprout" | "mushroom" | "acorn" | "cactus" | "pear" | "apple" | "strawberry" | "cherry" | "star" | "heart" | "flame" | "bell" | "ghost" | "bot" | "crescent" | "boba" | "fish" | "octopus" | "cat" | "bunny" | "bear" | "chick" | "penguin" | "pig" | "fox" | "bob" | "topknot" | "spiky" | "curly" | "twinbuns"——
    classNamestring——
    colorsreadonly ("black" | "brown" | "red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "violet" | "magenta" | "pink" | "gray")[]—Restrict the offered colours.
    face"cute" | "eyes" | "line"—Face style. Passing this shows the face toggle; in line mode a row of noses follows. Omit it to keep the picker to shape and colour.
    layout"grid" | "row"'grid'`grid` stacks shapes over colours in fixed columns; `row` keeps both groups on one line.
    lineWeightnumber—Line weight for the previews, so a picker matches the character it edits.
    nose"slant" | "angular" | "hook" | "long" | "curve" | "bow" | null—Nose for the line face. Defaults to the first nose while `face` is `line`. `null` — the same "no nose" every other surface takes — also lands on the first nose, because the picker has to highlight one of the offered options and "none" is not one of them.
    onSelectColor((color: "black" | "brown" | "red" | "orange" | "yellow" | "green" | "cyan" | "blue" | "violet" | "magenta" | "pink" | "gray") => void)——
    onSelectFace((face: "cute" | "eyes" | "line") => void)——
    onSelectNose((nose: "slant" | "angular" | "hook" | "long" | "curve" | "bow") => void)——
    onSelectShape((shape: "mochi" | "circle" | "blob" | "pebble" | "egg" | "bun" | "tofu" | "pill" | "hex" | "onigiri" | "gem" | "cloud" | "drop" | "leaf" | "flower" | "clover" | "sprout" | "mushroom" | "acorn" | "cactus" | "pear" | "apple" | "strawberry" | "cherry" | "star" | "heart" | "flame" | "bell" | "ghost" | "bot" | "crescent" | "boba" | "fish" | "octopus" | "cat" | "bunny" | "bear" | "chick" | "penguin" | "pig" | "fox" | "bob" | "topknot" | "spiky" | "curly" | "twinbuns") => void)——
    shapesreadonly ("mochi" | "circle" | "blob" | "pebble" | "egg" | "bun" | "tofu" | "pill" | "hex" | "onigiri" | "gem" | "cloud" | "drop" | "leaf" | "flower" | "clover" | "sprout" | "mushroom" | "acorn" | "cactus" | "pear" | "apple" | "strawberry" | "cherry" | "star" | "heart" | "flame" | "bell" | "ghost" | "bot" | "crescent" | "boba" | "fish" | "octopus" | "cat" | "bunny" | "bear" | "chick" | "penguin" | "pig" | "fox" | "bob" | "topknot" | "spiky" | "curly" | "twinbuns")[]SHAPE_IDSRestrict the offered shapes.
    showSelectionbooleantrueHide the selection ring, for read-only displays. The selection is still announced.
    sizePxnumber—Size of each shape preview. Face and nose previews scale with it. Defaults to `PICKER_MARK_PX`.
    styleCSSProperties——

    Next