Cradova Documentation

Learn how to build amazing web applications with Cradova

Cradova Components

This guide covers creating components and using DOM elements in Cradova.

Creating Components

Components are regular functions that receive ctx for state and lifecycle:

// ✅ CORRECT - regular function with ctx
const MyComponent = function(ctx: Comp) {
  const [count, setCount] = ctx.useState(0);
  
  return div(
    h1("Hello World"),
    p("Count: " + count),
    button("Click", { onclick: () => setCount(c => c + 1) })
  );
};

// ❌ WRONG - arrow functions don't get ctx
const Broken = () => { /* can't use hooks */ };

Component Structure

const Card = function(ctx: Comp) {
  // 1. Local state
  const [active, setActive] = ctx.useState(false);
  
  // 2. Effects for lifecycle
  ctx.useEffect(() => {
    console.log("Card mounted");
    return () => console.log("Card unmounted");
  }, []);
  
  // 3. Memoized values
  const cardClass = ctx.useMemo(() => 
    active ? "card active" : "card", 
  [active]);
  
  // 4. Render
  return div(
    { className: cardClass },
    h2("Card Title"),
    p("Card content here"),
    button(active ? "Active" : "Inactive", {
      onclick: () => setActive(!active)
    })
  );
};

Primitive DOM Elements

Cradova provides all standard HTML elements:

import { 
  div, p, span, 
  h1, h2, h3, h4, h5, h6,
  button, input, textarea, select,
  img, a, 
  ul, ol, li,
  table, tr, td,
  form, label,
  section, header, footer, nav, main,
  video, audio, canvas, iframe
} from "cradova";

Basic Usage

// Element with content
div("Hello World")

// Element with children
div(
  h1("Title"),
  p("Description")
)

// Element with props
div(
  { className: "container", id: "main" },
  h1("Title")
)

// Event handlers
button("Click me", {
  onclick() {
    console.log("Clicked!");
  }
})

Props and Attributes

// Class, ID, style
div(
  { 
    className: "my-class another-class",
    id: "unique-id",
    style: { color: "red", fontSize: "16px" }
  },
  "Content"
)

// Data and aria attributes
div({
  "data-user-id": "123",
  "aria-label": "Click here",
  "aria-expanded": "false"
})

// Boolean attributes
input({ 
  type: "checkbox", 
  checked: true,
  disabled: false 
})

Raw HTML

Use raw() for raw HTML injection:

import { raw, div } from "cradova";

// With template string
const CustomHTML = raw(`
  <div class="custom">
    <h2>Raw HTML Content</h2>
    <p>This is injected directly</p>
  </div>
`);

// Use in component
div(
  h1("Section"),
  CustomHTML
)

References (useRef)

Get DOM element references:

const FormExample = function(ctx: Comp) {
  const inputRef = ctx.useRef<HTMLInputElement>();
  const containerRef = ctx.useRef<HTMLElement>();
  
  const handleClick = () => {
    // Access element by name
    const input = inputRef.current("username");
    console.log("Input value:", input?.value);
    
    // Get container
    const container = containerRef.current("form-container");
    container?.classList.add("submitted");
  };
  
  return div(
    { ref: containerRef.bind("form-container") },
    input({ 
      ref: inputRef.bind("username"),
      type: "text",
      placeholder: "Enter name"
    }),
    button("Submit", { onclick: handleClick })
  );
};

Element Creation Flow

import { div, h1, button } from "cradova"

element(args) → makeElement() → append to DOM
     ↓
  [children, props, text]
     ↓
  Process in order:
  1. Functions → execute (if regular) or call (if arrow)
  2. Arrays → unroll and append
  3. Objects → apply as props/attributes
  4. Strings → set as textContent

Event Handlers

// Click handler
button("Click", {
  onclick() {
    console.log("Clicked");
  }
})

// Input handler
input({
  oninput(e: Event) {
    const value = (e.target as HTMLInputElement).value;
    console.log(value);
  }
})

// Form handler
form({
  onsubmit(e: Event) {
    e.preventDefault();
    console.log("Submitted");
  }
})

Children Pattern

// Pass component as child
const Card = function(ctx: Comp) {
  return div({ className: "card" }, ctx.children);
};

// Use with children
div(
  Card({ children: h1("Title") }),
  Card({ children: p("Description") })
)

Conditional Classes

const Card = function(ctx: Comp) {
  // 1. Local state
  const [active, setActive] = ctx.useState(false);
  
  // 2. Effects for lifecycle
  ctx.useEffect(() => {
    console.log("Card mounted");
    return () => console.log("Card unmounted");
  }, []);
  
  // 3. Memoized values
  const cardClass = ctx.useMemo(() => 
    active ? "card active" : "card", 
  [active]);
  
  // 4. Render
  return div(
    { className: cardClass },
    h2("Card Title"),
    p("Card content here"),
    button(active ? "Active" : "Inactive", {
      onclick: () => setActive(!active)
    })
  );
};
```0

## invoke - Component with Arguments

Use `invoke` to render a component with additional arguments:

```ts
const Card = function(ctx: Comp) {
  // 1. Local state
  const [active, setActive] = ctx.useState(false);
  
  // 2. Effects for lifecycle
  ctx.useEffect(() => {
    console.log("Card mounted");
    return () => console.log("Card unmounted");
  }, []);
  
  // 3. Memoized values
  const cardClass = ctx.useMemo(() => 
    active ? "card active" : "card", 
  [active]);
  
  // 4. Render
  return div(
    { className: cardClass },
    h2("Card Title"),
    p("Card content here"),
    button(active ? "Active" : "Inactive", {
      onclick: () => setActive(!active)
    })
  );
};
```1

## Fragment - Grouping Elements

Use `fragment` (or `frag`) to group elements without extra DOM nodes:

```ts
const Card = function(ctx: Comp) {
  // 1. Local state
  const [active, setActive] = ctx.useState(false);
  
  // 2. Effects for lifecycle
  ctx.useEffect(() => {
    console.log("Card mounted");
    return () => console.log("Card unmounted");
  }, []);
  
  // 3. Memoized values
  const cardClass = ctx.useMemo(() => 
    active ? "card active" : "card", 
  [active]);
  
  // 4. Render
  return div(
    { className: cardClass },
    h2("Card Title"),
    p("Card content here"),
    button(active ? "Active" : "Inactive", {
      onclick: () => setActive(!active)
    })
  );
};
```2

## Best Practices

1. **Use regular functions** - Required for ctx access
2. **Type your components** - Use `Comp` type for ctx
3. **Return single root** - Wrap multiple elements in div
4. **Extract complex logic** - Use hooks for reusability
5. **Use semantic HTML** - Use proper elements (nav, header, etc.)
6. **Handle events properly** - Use proper event types

Get Started in Minutes

Simple Setup

Follow our clear documentation to get your first project running in no time.

Write Less Code

Focus on your application's logic, not boilerplate.

Join the Discord

Get support and share your creations with a growing community.

Join Discord