Skip to content

Custom controls ​

Mount your own toolbar below the character. Mimimo hosts a real DOM element; your application owns its behavior. Use textContent for labels and clean up your own listeners.

Try it. It’s alive.LIVE DEMO

Drag the pet, or focus it and use arrow keys. Reduced motion follows your system settings.

Preparing example…

Signature ​

ts
pet.setPanel(content: HTMLElement | null): void
Parameter or methodBehavior
setPanel(element / null)Replaces/removes the custom lower panel.
setBubbleClose(element / null)Replaces/restores the bubble close control.
elementHost element for classes, CSS variables and shadow parts.

How it works ​

setPanel moves the provided element into the pet; it does not clone it. Passing null restores built-in chat if configured. setBubbleClose installs a custom close button but does not attach its click handler. Use a framework-managed wrapper or explicitly dispose any framework root you mount into the panel.

Use it in your project ​

Choose your stack. Each example includes setup and cleanup. For Vanilla, pass a mounted container at least 360px tall and keep the returned cleanup. Method names are identical across frameworks.

ts
import { createPet } from '@flowscape-ui/mimimo';
import { mochi } from '@flowscape-ui/mimimo-pet-mochi';

// Call after your container mounts.
export function mountCompanion(container: HTMLElement) {
  const lifetime = new AbortController();
  const pet = createPet({
    character: mochi,
    container,
    anchor: 'center',
  });
  const button = document.createElement('button');
  button.textContent = 'High five!';
  button.addEventListener('click', () => pet.react('happy'), {
    signal: lifetime.signal,
  });
  pet.setPanel(button);
  return () => {
    lifetime.abort();
    pet.destroy();
  };
}
// Keep the returned cleanup and call it when the view is removed.
tsx
'use client';
import { useEffect, useRef } from 'react';
import { createPet } from '@flowscape-ui/mimimo';
import { mochi } from '@flowscape-ui/mimimo-pet-mochi';

export default function Companion() {
  const host = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const container = host.current;
    if (!container) return;
    const lifetime = new AbortController();
    const pet = createPet({
      character: mochi,
      container,
      anchor: 'center',
    });
    const button = document.createElement('button');
    button.textContent = 'High five!';
    button.addEventListener('click', () => pet.react('happy'), {
      signal: lifetime.signal,
    });
    pet.setPanel(button);
    return () => {
      lifetime.abort();
      pet.destroy();
    };
  }, []);
  return <div ref={host} style={{ height: 360, position: 'relative' }} />;
}
vue
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { createPet } from '@flowscape-ui/mimimo';
import { mochi } from '@flowscape-ui/mimimo-pet-mochi';
const host = ref<HTMLElement | null>(null);
let cleanup: (() => void) | undefined;
onMounted(() => {
  const container = host.value;
  if (!container) return;
  const lifetime = new AbortController();
  const pet = createPet({
    character: mochi,
    container,
    anchor: 'center',
  });
  const button = document.createElement('button');
  button.textContent = 'High five!';
  button.addEventListener('click', () => pet.react('happy'), {
    signal: lifetime.signal,
  });
  pet.setPanel(button);
  cleanup = () => {
    lifetime.abort();
    pet.destroy();
  };
});
onBeforeUnmount(() => cleanup?.());
</script>

<template>
  <div ref="host" style="height: 360px; position: relative" />
</template>

All capabilities · Environments

Style the bubble ​

ts
pet.element.classList.add('my-companion');
css
.my-companion {
  --mimimo-accent: #ffbe3d;
  --mimimo-bubble-background: #fff5e6;
  --mimimo-bubble-color: #171419;
  --mimimo-bubble-muted: #5f5264;
  --mimimo-bubble-width: 240px;
  --mimimo-bubble-radius: 16px;
}
.my-companion::part(title) {
  font-weight: 800;
}

Little companions, made by Flowscape Team.