Skip to content

Learn By Example

manolo edge edited this page Jul 6, 2025 · 9 revisions

The best way to learn is by example.

This guide shows practical examples and explanations for the basics of Cardboard.


Cardboard Basics


0. Initializing Cardboard

Every Cardboard app starts by calling init(). This sets up the framework and creates a root element (by default, the <body> tag) to which you can append your UI.

import { init } from '@nkeff/cardboard-js';

const root = init(); // The <body> is now your root element

You can also specify a different selector if you want to mount your app to a different element:

const root = init({ selector: '#app-root' });

This is the first step in any Cardboard app. The init function returns the root element for your UI.

↑ Go to top


1. Creating a tag

Use the allTags object to create any HTML tag as a function. This is the core of Cardboard's declarative API.

import { init, allTags } from '@nkeff/cardboard-js';

const { div } = allTags;

init().append(
  div() // creates a <div></div>
);
  • allTags provides factory functions for all standard HTML tags.

↑ Go to top


2. Adding text to a tag

You can add text directly as a string, or use the text function for dynamic or templated text.

import { init, allTags, text } from '@nkeff/cardboard-js';
const { p } = allTags;

init().append(
  p('Hello, Cardboard!'),                            // <p>Hello, Cardboard!</p>
  p(text('Hello, ${name}!', { name: 'world!' })),    // <p>Hello, world!</p>
);
  • Direct string: p('Hello, Cardboard!')
  • Dynamic: text for string templates and reactivity.

See: Managing Text

↑ Go to top


3. Creating nested elements

Tags can take other tags as children, allowing you to build complex structures.

import { init, allTags } from '@nkeff/cardboard-js';

const { ul, li } = allTags;
init().append(
  ul(
    li('Item 1'),
    li('Item 2'),
    li('Item 3')
  )
);

See: Tags

↑ Go to top


4. Setting attributes

Set HTML attributes using .setAttrs().

import { init, allTags } from '@nkeff/cardboard-js';

const { input } = allTags;
init().append(
  input().setAttrs({ placeholder: 'Type here', type: 'text' })
);

See: Manipulating Tags

↑ Go to top


5. Adding and removing classes

Add or remove CSS classes using .addClass() and .rmClass().

import { init, allTags } from '@nkeff/cardboard-js';

const { div } = allTags;
const box = div('Box').addClass('my-class');
box.rmClass('my-class');

init().append(box);

See: Manipulating Tags

↑ Go to top


6. Setting styles

Apply inline styles with .setStyle(). This is best for quick prototyping or dynamic changes.

import { init, allTags } from '@nkeff/cardboard-js';

const { div } = allTags;
init().append(
  div('Styled box').setStyle({
    color: 'white',
    background: 'blue',
    padding: '16px',
    borderRadius: '8px',
  })
);

See: Styling

↑ Go to top


7. Adding event listeners

Attach event listeners to tags using .on() or convenience methods like .clicked().

import { init, allTags } from '@nkeff/cardboard-js';

const { button } = allTags;
init().append(
  button('Click me').on('click', (self, evt) => {
    self.text('Clicked!');
  })
);

See: .on, once, when

↑ Go to top


Advanced Cardboard


1. Using state for reactivity

Cardboard's state function creates reactive values. When you update a state, the UI updates automatically.

import { init, allTags, state } from '@nkeff/cardboard-js';

const { button, p } = allTags;
const count = state(0);

init().append(
  p().text('Count: $count', { count }),
  button('Increase').clicked(() => count.value++)
);

See: State

↑ Go to top


2. Dynamic lists with state and each

Render dynamic lists using each and a reactive state array.

import { init, allTags, state, each } from '@nkeff/cardboard-js';

const { ul, li, button, input } = allTags;
const items = state(['Apple', 'Banana']);

const addItem = (item) => {
  if (item) items.value = [...items.value, item];
};

let inputRef;
init().append(
  input().on('input', (self) => (inputRef = self.value)),
  button('Add').clicked(() => addItem(inputRef)),
  ul(
    each(items, (item) => li(item))
  )
);

See: Rendering Lists

↑ Go to top


3. Conditional rendering (show/hide elements)

Show or hide elements based on state using .hideIfNot().

import { init, allTags, state } from '@nkeff/cardboard-js';

const { div, button, p } = allTags;
const show = state(true);

init().append(
  button('Toggle').clicked(() => (show.value = !show.value)),
  div(
    p('This is conditionally visible!')
  ).hideIfNot(show)
);

See: Conditional Rendering

↑ Go to top


4. Two-way binding with input

Bind an input's value to state and reflect changes in the UI.

import { init, allTags, state } from '@nkeff/cardboard-js';

const { input, p } = allTags;
const textValue = state('');

init().append(
  input().setAttrs({ placeholder: 'Type...' })
    .on('input', (self) => (textValue.value = self.value)),
  p().text('You typed: $textValue', { textValue })
);

See: State

↑ Go to top


5. Styling with classes and dynamic styles

Dynamically add or remove classes based on state using .classIf().

import { init, allTags, state } from '@nkeff/cardboard-js';

const { button, div } = allTags;
const active = state(false);

init().append(
  button('Toggle highlight').clicked(() => (active.value = !active.value)),
  div('Highlight me!')
    .addClass('highlight')
    .classIf(active, ['active'])
    .setStyle({ padding: '16px', border: '1px solid #ccc' })
);

// Add your own CSS for .highlight and .active in your stylesheet

See: Styling

↑ Go to top


6. Composing reusable components

Build reusable components by composing tags and state.

import { init, allTags, state } from '@nkeff/cardboard-js';
const { div, button, p } = allTags;

function Counter(label = 'Counter') {
  const count = state(0);

  return div(
    p(`${label}: $count`, count),
    button('Increment').clicked(() => count.value++)
  );
}

init().append(
  Counter('A'),
  Counter('B')
);

See: Reusable Components

↑ Go to top


More on Styling

While inline styles (setStyle) are convenient for quick prototyping or dynamic changes, it's best to use CSS classes and the .styled() method or <style> tags for reusable or large-scale components. This keeps your styles organized, efficient, and avoids unnecessary duplication in the DOM.


7. Using .styled() for reusable component styles

import { init, allTags } from '@nkeff/cardboard-js';
const { div } = allTags;

// Define a style object for reuse
const cardStyle = {
  backgroundColor: '#466187',
  borderRadius: '16px',
  color: 'white',
  padding: '16px',
  margin: '10px',
  ':hover': {
    color: 'lightblue',
  }
};

function Card(content: string) {
  return div(content).styled(cardStyle, 'my-card');
}

init().append(
  Card('Reusable styled card'),
  Card('Another card')
);

This example uses the .styled() method to apply a CSS class with the given styles. The style is injected only once, no matter how many components use it.

See: styled

↑ Go to top


8. Adding global styles with the style tag

import { init, allTags } from '@nkeff/cardboard-js';
const { div, style } = allTags;

init().append(
  style({
    '.fancy': {
      background: 'linear-gradient(90deg, #f3ec78, #af4261)',
      color: '#222',
      padding: '12px 24px',
      borderRadius: '8px',
      fontWeight: 'bold',
    }
  }),
  div('This uses a global class!').addClass('fancy')
);

Here, a global style is defined using the style tag and then applied via addClass. This is the most efficient way to style many elements.

See: style tag

↑ Go to top


9. Avoiding inline styles for performance

Inline styles (via .setStyle) are best for dynamic, one-off, or state-driven changes. For static or repeated styles, prefer .styled() or global classes. This reduces DOM bloat and improves performance, especially with many elements.

import { allTags } from '@nkeff/cardboard-js';
const { div } = allTags;

// BAD: Each instance gets its own inline style
const cmp1 = () => div('Not recommended').setStyle({ color: 'red', fontWeight: 'bold' });

// GOOD: Use a class or .styled() for shared styles
const cmp2 = () => div('Recommended').addClass('my-shared-style');

Define .my-shared-style in a global style block or with .styled().


See also: Styling Guide, styled, setStyle

More examples

Clone this wiki locally