Keyboard
No component-specific keymap. Inherits standard browser focus / activation behaviour.
Svelte 5 {@attach} factories. Glue ARIA / keyboard / focus onto any DOM node you choose. **Best when you want full control over markup and styling.**
<script lang="ts">
import { createAvatarGroup } from '@kumiki/headless/avatar-group';
const ctl = createAvatarGroup({});
</script>
<div {@attach ctl.root}>
<!-- your markup -->
</div>Compound components (<Root> / <Trigger> / …). Markup is fixed; styling is not. Same trade-off as a typical headless UI library.
pnpm add @kumiki/components<AvatarGroup.Root max={3} total={users.length} aria-label="Project members">
{#each users.slice(0, 3) as u (u.id)}
<AvatarGroup.Item>
<Avatar.Root decorative>
<Avatar.Image src={u.photo} />
<Avatar.Fallback>{u.name[0]}</Avatar.Fallback>
</Avatar.Root>
</AvatarGroup.Item>
{/each}
<AvatarGroup.Overflow />
</AvatarGroup.Root>Styled, copy-paste presets (preview). Run pnpm kumiki add to drop the source into your project, then edit freely.
Live preview…
pnpm add @kumiki/atelier<script lang="ts">
import { Tailwind as AvatarGroup } from '@kumiki/atelier/avatar-group';
const members = [
{ id: '1', name: 'Akari', src: '/u/1.jpg' },
{ id: '2', name: 'Ben', src: '/u/2.jpg' },
{ id: '3', name: 'Cora', src: '/u/3.jpg' },
{ id: '4', name: 'Dai', src: '/u/4.jpg' },
];
</script>
<AvatarGroup.Root max={3} aria-label="Project members">
{#each members as m (m.id)}
<AvatarGroup.Item src={m.src} alt={m.name} />
{/each}
<AvatarGroup.Overflow />
</AvatarGroup.Root>/ accessibility
axe-core — run on every PR (LTR + RTL × every documented state).
No component-specific keymap. Inherits standard browser focus / activation behaviour.