A playful, animation-rich Web Component library for kids
# Install via npm
npm install @openkids/kidsui
Then import in your JavaScript:
import '@openkids/kidsui';
<!-- Add this to your HTML head -->
<script type="module" src="https://unpkg.com/@openkids/kidsui/dist/kidsui.js"></script>
Or download and use locally:
<script type="module" src="./dist/kidsui.js"></script>
<!-- Just use the tags! -->
<kids-button variant="primary">Click me!</kids-button>
<kids-card hoverable>
<span slot="header">My Card</span>
Hello from KidsUI!
</kids-card>
<kids-badge variant="accent" animate="bounce">New!</kids-badge>
That's it! KidsUI components work like native HTML elements.
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "primary" | Button style: primary, secondary, accent, warning |
size |
string | "md" | Button size: sm, md, lg |
disabled |
boolean | false | Disables the button interaction |
<!-- Basic usage -->
<kids-button variant="primary">Click Me!</kids-button>
<!-- Different variants -->
<kids-button variant="secondary">Hello!</kids-button>
<kids-button variant="accent" size="lg">Big Button</kids-button>
<kids-button variant="warning" size="sm">Tiny</kids-button>
<!-- Disabled state -->
<kids-button disabled>Disabled</kids-button>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "default" | Card style: default, outlined |
hoverable |
boolean | false | Adds lift effect on hover |
| Name | Description |
|---|---|
(default) | Main card content |
header | Card header area |
footer | Card footer area |
<!-- Basic card with hover effect -->
<kids-card hoverable>
<span slot="header">Card Title</span>
Card content goes here!
</kids-card>
<!-- Outlined card with footer -->
<kids-card variant="outlined">
<span slot="header">Outlined Card</span>
Secondary content
<span slot="footer">
<kids-button variant="secondary" size="sm">Action</kids-button>
</span>
</kids-card>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "primary" | Badge color: primary, secondary, accent, warning, info |
animate |
string | "none" | Animation: none, pulse, wiggle, bounce |
<!-- Static badge -->
<kids-badge variant="primary">New!</kids-badge>
<!-- Animated badges -->
<kids-badge variant="secondary" animate="pulse">Pulse</kids-badge>
<kids-badge variant="accent" animate="wiggle">Wiggle</kids-badge>
<kids-badge variant="warning" animate="bounce">Bounce</kids-badge>
| Name | Type | Default | Description |
|---|---|---|---|
checked |
boolean | false | Whether the toggle is on |
disabled |
boolean | false | Disables the toggle |
variant |
string | "primary" | Color: primary, secondary, accent |
size |
string | "md" | Size: sm, md, lg |
<!-- Basic toggle -->
<kids-toggle variant="primary">Sound</kids-toggle>
<!-- Pre-checked toggle -->
<kids-toggle checked>Enabled</kids-toggle>
<!-- Large accent toggle -->
<kids-toggle variant="accent" size="lg">Dark Mode</kids-toggle>
<!-- Listen for changes -->
<script>
document.querySelector('kids-toggle').addEventListener('kids-toggle', (e) => {
console.log('Toggled:', e.detail.checked);
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
placeholder |
string | "" | Placeholder text |
value |
string | "" | Current value |
type |
string | "text" | Input type: text, password, number, email |
disabled |
boolean | false | Disables the input |
variant |
string | "default" | Style: default, outlined |
size |
string | "md" | Size: sm, md, lg |
<!-- Basic input -->
<kids-input placeholder="What's your name?"></kids-input>
<!-- Outlined variant -->
<kids-input variant="outlined"></kids-input>
<!-- Different sizes -->
<kids-input size="sm"></kids-input>
<kids-input size="lg"></kids-input>
<!-- Listen for input -->
<script>
document.querySelector('kids-input').addEventListener('kids-input', (e) => {
console.log('Value:', e.detail.value);
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
value |
number | 0 | Progress value (0–100) |
variant |
string | "primary" | Color: primary, secondary, accent, warning, info |
size |
string | "md" | Height: sm, md, lg |
striped |
boolean | false | Adds animated diagonal stripes |
label |
boolean | false | Shows percentage text |
<!-- Basic progress bar -->
<kids-progress value="75"></kids-progress>
<!-- With label and stripes -->
<kids-progress value="60" striped label></kids-progress>
<!-- Different sizes and variants -->
<kids-progress value="45" variant="secondary" size="lg"></kids-progress>
<kids-progress value="30" variant="warning" size="sm"></kids-progress>
| Name | Type | Default | Description |
|---|---|---|---|
src |
string | "" | Image URL (shows image if provided, otherwise shows slot content) |
size |
string | "md" | Size: sm, md, lg, xl |
variant |
string | "primary" | Background color for initials mode: primary, secondary, accent, warning, info |
| Name | Description |
|---|---|
(default) | Initials text (shown when no src) |
<!-- Image avatar -->
<kids-avatar src="https://api.dicebear.com/7.x/avataaars/svg?seed=Felix"></kids-avatar>
<!-- Different sizes -->
<kids-avatar src="..." size="sm"></kids-avatar>
<kids-avatar src="..." size="lg"></kids-avatar>
<!-- Initials avatar -->
<kids-avatar variant="primary" size="xl">JD</kids-avatar>
<kids-avatar variant="accent">AB</kids-avatar>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "info" | Alert type: info, success, warning, error |
dismissible |
boolean | false | Shows a close button |
<!-- Info alert -->
<kids-alert variant="info">This is an informational message!</kids-alert>
<!-- Success alert -->
<kids-alert variant="success">Great job!</kids-alert>
<!-- Dismissible warning -->
<kids-alert variant="warning" dismissible>Watch out!</kids-alert>
<!-- Listen for dismiss -->
<script>
document.querySelector('kids-alert').addEventListener('kids-dismiss', () => {
console.log('Alert dismissed');
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "solid" | Line style: solid, dashed, dotted, wavy |
color |
string | "primary" | Line color: primary, secondary, accent, warning, info |
spacing |
string | "md" | Vertical spacing: sm, md, lg |
| Name | Description |
|---|---|
(default) | Optional center label |
<!-- Simple divider -->
<kids-divider color="primary"></kids-divider>
<!-- Dashed with label -->
<kids-divider variant="dashed" color="secondary">or</kids-divider>
<!-- Wavy divider -->
<kids-divider variant="wavy" color="warning"></kids-divider>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "primary" | Color: primary, secondary, accent, warning, info |
removable |
boolean | false | Shows a close button |
selected |
boolean | false | Filled/active style |
size |
string | "md" | Size: sm, md |
<!-- Basic chip -->
<kids-chip variant="primary">Science</kids-chip>
<!-- Selected chip -->
<kids-chip selected>Math</kids-chip>
<!-- Removable chip -->
<kids-chip removable>Art</kids-chip>
<!-- Listen for events -->
<script>
document.querySelector('kids-chip').addEventListener('kids-remove', () => {
console.log('Chip removed');
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
text |
string | "" | The tooltip text to display |
position |
string | "top" | Position: top, bottom, left, right |
variant |
string | "dark" | Tooltip style: dark, primary, secondary |
| Name | Description |
|---|---|
(default) | The trigger element |
<!-- Tooltip on top -->
<kids-tooltip text="I'm on top!" position="top">
<kids-button>Hover me</kids-button>
</kids-tooltip>
<!-- Different positions and variants -->
<kids-tooltip text="Down here!" position="bottom" variant="primary">
<kids-button>Bottom</kids-button>
</kids-tooltip>
| Name | Type | Default | Description |
|---|---|---|---|
size |
string | "md" | Size: sm, md, lg |
variant |
string | "primary" | Color: primary, secondary, accent, warning, info |
type |
string | "spin" | Animation style: spin, dots, bounce |
<!-- Classic spinner -->
<kids-spinner></kids-spinner>
<!-- Dots animation -->
<kids-spinner type="dots"></kids-spinner>
<!-- Bouncing ball -->
<kids-spinner type="bounce" size="lg"></kids-spinner>
| Name | Type | Default | Description |
|---|---|---|---|
name |
string | "" | Radio group name |
value |
string | "" | The value this radio represents |
checked |
boolean | false | Whether this radio is selected |
disabled |
boolean | false | Disables the radio |
variant |
string | "primary" | Color: primary, secondary, accent |
<!-- Radio group -->
<kids-radio name="fruit" value="apple" checked>Apple</kids-radio>
<kids-radio name="fruit" value="banana">Banana</kids-radio>
<kids-radio name="fruit" value="cherry">Cherry</kids-radio>
<!-- Listen for selection -->
<script>
document.querySelectorAll('kids-radio').forEach(radio => {
radio.addEventListener('kids-radio-change', (e) => {
console.log('Selected:', e.detail.value);
});
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
checked |
boolean | false | Whether the checkbox is checked |
disabled |
boolean | false | Disables the checkbox |
variant |
string | "primary" | Color: primary, secondary, accent |
<!-- Basic checkbox -->
<kids-checkbox>I agree to terms</kids-checkbox>
<!-- Pre-checked with variant -->
<kids-checkbox variant="accent" checked>Enable rainbows</kids-checkbox>
<!-- Listen for changes -->
<script>
document.querySelector('kids-checkbox').addEventListener('kids-checkbox-change', (e) => {
console.log('Checked:', e.detail.checked);
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
placeholder |
string | "" | Placeholder text |
rows |
number | 4 | Number of visible rows |
disabled |
boolean | false | Disables the textarea |
value |
string | "" | Initial text content |
variant |
string | "default" | Style: default, outlined |
<!-- Basic textarea -->
<kids-textarea placeholder="Write your story..." rows="3"></kids-textarea>
<!-- Outlined variant -->
<kids-textarea variant="outlined" rows="2"></kids-textarea>
| Name | Type | Default | Description |
|---|---|---|---|
placeholder |
string | "Pick one!" | Text when nothing selected |
disabled |
boolean | false | Disables the select |
value |
string | "" | Currently selected value |
variant |
string | "default" | Style: default, outlined |
<option value="...">Label</option> — Option elements
<!-- Basic select -->
<kids-select placeholder="Pick a fruit!">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
</kids-select>
<!-- Outlined variant -->
<kids-select variant="outlined">...</kids-select>
<!-- Listen for selection -->
<script>
document.querySelector('kids-select').addEventListener('kids-change', (e) => {
console.log('Selected:', e.detail.value, e.detail.label);
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
active |
number | 0 | Index of the active tab |
variant |
string | "default" | Style: default, pills |
<!-- Default tabs -->
<kids-tabs active="0">
<kids-tab label="Story">Once upon a time...</kids-tab>
<kids-tab label="Quiz">Question here</kids-tab>
<kids-tab label="Activity">Draw something!</kids-tab>
</kids-tabs>
<!-- Pills variant -->
<kids-tabs variant="pills">...</kids-tabs>
This is a playful dialog box. You can put anything inside!
| Name | Type | Default | Description |
|---|---|---|---|
open |
boolean | false | Controls visibility |
title |
string | "" | Dialog heading text |
size |
string | "md" | Dialog width: sm, md, lg |
| Name | Description |
|---|---|
(default) | Dialog body content |
footer | Action buttons area |
<!-- Dialog trigger -->
<kids-button onclick="document.getElementById('my-dialog').setAttribute('open','')">
Open Dialog
</kids-button>
<!-- Dialog definition -->
<kids-dialog id="my-dialog" title="Hello!">
<p>Dialog content goes here.</p>
<span slot="footer">
<kids-button onclick="document.getElementById('my-dialog').removeAttribute('open')">
Close
</kids-button>
</span>
</kids-dialog>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "info" | Toast type: info, success, warning, error |
duration |
number | 4000 | Auto-dismiss time in ms (0 to disable) |
position |
string | "top-right" | Position: top-right, top-left, bottom-right, bottom-left, top-center, bottom-center |
open |
boolean | false | Controls visibility |
<!-- Toast trigger -->
<kids-button onclick="document.getElementById('my-toast').setAttribute('open','')">
Show Toast
</kids-button>
<!-- Toast definition -->
<kids-toast id="my-toast" variant="success" duration="3000" position="top-right">
Great job! You earned a star!
</kids-toast>
| Name | Type | Default | Description |
|---|---|---|---|
min |
number | 0 | Minimum value |
max |
number | 100 | Maximum value |
value |
number | 50 | Current value |
step |
number | 1 | Step increment |
disabled |
boolean | false | Disables the slider |
variant |
string | "primary" | Track color: primary, secondary, accent |
label |
string | "" | Optional label text (shows value) |
<!-- Basic slider -->
<kids-slider label="Volume" value="60"></kids-slider>
<!-- Custom range -->
<kids-slider label="Difficulty" value="30" min="0" max="100"></kids-slider>
<!-- Different variant -->
<kids-slider variant="accent"></kids-slider>
| Name | Type | Default | Description |
|---|---|---|---|
multiple |
boolean | false | Allow multiple items open at once |
| Name | Type | Default | Description |
|---|---|---|---|
label |
string | "" | Header text |
open |
boolean | false | Whether expanded |
<!-- Basic accordion -->
<kids-accordion>
<kids-accordion-item label="Question 1?" open>
Answer goes here!
</kids-accordion-item>
<kids-accordion-item label="Question 2?">
Another answer!
</kids-accordion-item>
</kids-accordion>
<!-- Allow multiple open -->
<kids-accordion multiple>...</kids-accordion>
| Name | Type | Default | Description |
|---|---|---|---|
steps |
JSON array | [] | Array of step labels |
active |
number | 0 | Current step index (0-based) |
variant |
string | "default" | Style: default, compact |
<!-- Basic stepper -->
<kids-stepper
steps='["Step 1","Step 2","Step 3"]'
active="1"
></kids-stepper>
<!-- Compact variant -->
<kids-stepper variant="compact" steps='["A","B","C"]' active="0">
</kids-stepper>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "text" | Shape: text, circle, rect, card |
width |
string | "100%" | CSS width |
height |
string | varies | CSS height (defaults vary by variant) |
lines |
number | 1 | Number of text lines (only for variant="text") |
<!-- Text lines -->
<kids-skeleton variant="text" lines="2"></kids-skeleton>
<!-- Circle avatar placeholder -->
<kids-skeleton variant="circle" width="48px" height="48px"></kids-skeleton>
<!-- Card placeholder -->
<kids-skeleton variant="card" height="140px"></kids-skeleton>
| Name | Type | Default | Description |
|---|---|---|---|
value |
string | "" | The option value |
selected |
boolean | false | Whether currently selected |
correct |
boolean | false | Show as correct answer (green) |
incorrect |
boolean | false | Show as wrong answer (red shake) |
disabled |
boolean | false | Disables the card |
variant |
string | "default" | Layout: default, image |
<!-- Basic choice card -->
<kids-choice-card value="a">
Option A text
</kids-choice-card>
<!-- Selected state -->
<kids-choice-card value="b" selected>Option B</kids-choice-card>
<!-- Answer states -->
<kids-choice-card value="c" correct>Correct answer</kids-choice-card>
<kids-choice-card value="d" incorrect>Wrong answer</kids-choice-card>
| Name | Type | Default | Description |
|---|---|---|---|
variant |
string | "tip" | Callout type: tip, info, warning, fun-fact, remember |
title |
string | "" | Custom heading (overrides default) |
<!-- Tip callout -->
<kids-callout variant="tip">
Always read carefully!
</kids-callout>
<!-- Fun fact -->
<kids-callout variant="fun-fact">
Honey never spoils!
</kids-callout>
<!-- Custom title -->
<kids-callout variant="info" title="Custom Heading">
Content here
</kids-callout>
| Name | Type | Default | Description |
|---|---|---|---|
current |
number | 1 | Current lesson number (1-based) |
total |
number | 1 | Total number of lessons |
prev-label |
string | "Back" | Label for previous button |
next-label |
string | "Next" | Label for next button |
show-progress |
boolean | false | Show progress text |
<!-- Basic lesson nav -->
<kids-lesson-nav current="3" total="5"></kids-lesson-nav>
<!-- With progress indicator -->
<kids-lesson-nav current="2" total="8" show-progress></kids-lesson-nav>
<!-- Listen for navigation -->
<script>
document.querySelector('kids-lesson-nav').addEventListener('kids-next', () => {
console.log('Next clicked');
});
</script>
| Name | Type | Default | Description |
|---|---|---|---|
lessons |
JSON array | [] | Array of lesson objects with title and status (completed | current | locked) |
variant |
string | "list" | Layout: list, map |
<!-- Lesson progress tracker -->
<kids-lesson-progress lessons='[
{"title":"Intro","status":"completed"},
{"title":"Lesson 1","status":"completed"},
{"title":"Lesson 2","status":"current"},
{"title":"Quiz","status":"locked"}
]'></kids-lesson-progress>
<!-- Map variant -->
<kids-lesson-progress variant="map" lessons='[...]'></kids-lesson-progress>
| Name | Type | Default | Description |
|---|---|---|---|
number |
number | "" | Question number |
total |
number | "" | Total questions |
status |
string | "unanswered" | Status: unanswered, correct, incorrect, skipped |
points |
number | "" | Points value for this question |
| Name | Description |
|---|---|
question | The question text |
(default) | Answer options / interactive content |
hint | Optional hint text |
explanation | Shown after answering |
<!-- Question card -->
<kids-question-card number="3" total="10" points="5">
<span slot="question">Which planet...?</span>
<kids-choice-card value="a">Venus</kids-choice-card>
<kids-choice-card value="b">Mars</kids-choice-card>
<span slot="hint">Think about...</span>
</kids-question-card>
Which animals are mammals? (select multiple)
| Name | Type | Default | Description |
|---|---|---|---|
mode |
string | "single" | Selection mode: single, multiple |
value |
string | "" | Selected value(s), comma-separated for multiple |
disabled |
boolean | false | Disables all children |
direction |
string | "vertical" | Layout: vertical, horizontal, grid |
columns |
number | 2 | Number of grid columns (for direction="grid") |
<!-- Single select (default) -->
<kids-choice-group>
<kids-choice-card value="a">Option A</kids-choice-card>
<kids-choice-card value="b">Option B</kids-choice-card>
</kids-choice-group>
<!-- Multiple select grid -->
<kids-choice-group mode="multiple" direction="grid" columns="2">
<kids-choice-card value="dog">Dog</kids-choice-card>
<kids-choice-card value="cat">Cat</kids-choice-card>
</kids-choice-group>
| Name | Type | Default | Description |
|---|---|---|---|
icon |
string | "🎒" | Emoji or icon character |
title |
string | "Nothing here yet!" | Heading text |
message |
string | "" | Description text |
| Name | Description |
|---|---|
action | Optional CTA button/link |
<!-- Empty state -->
<kids-empty-state
icon="📚"
title="No lessons yet!"
message="Start your first lesson..."
>
<kids-button slot="action">Start Learning</kids-button>
</kids-empty-state>
| Name | Type | Default | Description |
|---|---|---|---|
icon |
string | "🏆" | Emoji or icon character |
title |
string | "Achievement Unlocked!" | Achievement title |
message |
string | "" | Description text |
variant |
string | "gold" | Badge style: gold, silver, bronze, special |
open |
boolean | false | Show the achievement |
<!-- Trigger button -->
<kids-button onclick="document.getElementById('achievement').setAttribute('open','')">
Unlock!
</kids-button>
<!-- Achievement popup -->
<kids-achievement
id="achievement"
icon="🏆"
title="Quiz Master!"
message="You scored 100%!"
variant="gold"
></kids-achievement>
| Name | Type | Default | Description |
|---|---|---|---|
flipped |
boolean | false | Whether showing the back side |
variant |
string | "default" | Size: default, compact |
| Name | Description |
|---|---|
front | Front face content (question/term) |
back | Back face content (answer/definition) |
<!-- Flashcard -->
<kids-flashcard>
<span slot="front">What is H₂O?</span>
<span slot="back">Water!</span>
</kids-flashcard>
<!-- Compact variant -->
<kids-flashcard variant="compact">...</kids-flashcard>
| Name | Type | Default | Description |
|---|---|---|---|
pairs |
JSON array | [] | Array of { left, right } objects |
status |
string | "playing" | Game state: playing, checking, completed |
shuffle |
boolean | true | Shuffle the right-side items |
<!-- Matching exercise -->
<kids-match-grid pairs='[
{"left":"Cat","right":"Meow"},
{"left":"Dog","right":"Woof"},
{"left":"Cow","right":"Moo"}
]'></kids-match-grid>
<!-- Listen for matches -->
<script>
document.querySelector('kids-match-grid').addEventListener('kids-match', (e) => {
console.log('Match:', e.detail.correct ? 'Correct!' : 'Try again');
});
</script>
Put the planets in order from the Sun:
| Name | Type | Default | Description |
|---|---|---|---|
items |
JSON array | [] | Array of items to sort |
correct |
JSON array | [] | Correct order (for checking) |
status |
string | "playing" | State: playing, correct, incorrect |
shuffle |
boolean | true | Shuffle items on init |
<!-- Sorting exercise -->
<kids-sort-list
items='["Earth","Venus","Mars","Mercury"]'
correct='["Mercury","Venus","Earth","Mars"]'
></kids-sort-list>
<!-- Check answer programmatically -->
<script>
const sortList = document.querySelector('kids-sort-list');
sortList.check(); // Returns true/false, triggers kids-check event
</script>
| Name | Type | Default | Description |
|---|---|---|---|
duration |
number | 60 | Total time in seconds |
mode |
string | "countdown" | Timer mode: countdown, countup |
running |
boolean | false | Starts/stops the timer |
variant |
string | "default" | Style: default, compact, circular |
warn-at |
number | 10 | Seconds remaining to show warning state |
reset() — Resets the timer to initial state<!-- Countdown timer -->
<kids-timer duration="60" running></kids-timer>
<!-- Circular variant -->
<kids-timer duration="120" variant="circular"></kids-timer>
<!-- Control timer -->
<script>
const timer = document.querySelector('kids-timer');
timer.setAttribute('running', ''); // Start
timer.removeAttribute('running'); // Pause
timer.reset(); // Reset
</script>