Basics
Fundamental concepts of the Hypen language
Basics
This guide covers the fundamental concepts of the Hypen language.
Components
Components are the building blocks of Hypen UIs. They're declared by name followed by optional arguments and children.
// Component with no arguments
Spacer()
// Component with arguments
Text("Hello World")
// Component with children
Column {
Text("First")
Text("Second")
}
// Component with arguments AND children
Button {
Text("Submit")
}.onClick(@actions.submit)Component Names
Component names are PascalCase (start with uppercase):
// Correct
Column { }
Text("Hi")
MyCustomComponent()
// Wrong - will be treated as unknown
column { }
text("Hi")Arguments
Arguments pass data to components. They can be positional or named.
Positional Arguments
Text("Hello") // Single positional
Image("photo.jpg") // URL as positionalNamed Arguments
Text(text: "Hello")
Input(placeholder: "Enter name")
.value(${state.name})Argument Types
// Strings (double or single quotes)
Text("Hello")
Text('Contains "double quotes" inside')
Text("Escaped \"quotes\" also work")
// Numbers
.padding(16)
.fontSize(24)
.opacity(0.5)
// Booleans
Button(disabled: true)
Input(multiline: false)
// Lists
Row(items: ["a", "b", "c"])
// Maps
Card(style: { elevation: 4, rounded: true })
// State bindings
Text("Count: ${state.count}")
// Actions (via applicators)
Button { Text("Save") }
.onClick(@actions.save)Applicators
Applicators modify a component's appearance or behavior. They're chained with dot notation.
Text("Styled text")
.fontSize(18)
.fontWeight("bold")
.color("#3B82F6")
.padding(16)Chaining
Applicators are applied in order, from top to bottom:
Box { }
.backgroundColor("blue") // Applied first
.padding(16) // Applied second
.borderRadius(8) // Applied thirdCommon Applicators
// Spacing
.padding(16)
.margin(8)
.gap(12)
// Size
.width(200)
.height(100)
.fillMaxWidth(true)
// Colors
.color("#333333")
.backgroundColor("#F3F4F6")
// Typography
.fontSize(18)
.fontWeight("bold")
.textAlign("center")
// Border
.borderRadius(8)
.borderWidth(1)
.borderColor("#E5E7EB")
// Layout
.horizontalAlignment("center")
.verticalAlignment("center")State Bindings
State bindings connect your UI to reactive data using ${state.path} syntax.
// Simple binding
Text("Hello, ${state.name}!")
// Nested paths
Text("${state.user.profile.displayName}")
// In string interpolation
Text("You have ${state.messages.length} messages")When the referenced state changes, the UI automatically updates.
Actions
Actions trigger handlers in your module using @actions.actionName syntax via event applicators.
// Basic action
Button { Text("Save") }
.onClick(@actions.save)
// Action with additional data
Button { Text("Delete") }
.onClick(@actions.deleteItem, id: ${state.currentId})
// Multiple events
Input(placeholder: "Type here")
.onInput(@actions.updateText)
.onFocus(@actions.inputFocused)
.onBlur(@actions.inputBlurred)Children
Components can contain other components as children using braces { }.
Column {
Text("First child")
Text("Second child")
Row {
Text("Nested child")
}
}Nesting
There's no limit to nesting depth:
Column {
Card {
Row {
Image("avatar.png")
Column {
Text("John Doe")
Text("@johndoe")
}
}
}
}Control Flow
Hypen provides first-class control flow components for building dynamic UIs. These don't create DOM elements — their children render directly into the parent. For a complete guide, see Control Flow.
ForEach — Rendering Lists
Iterate over an array from state and render children for each item. Use @item to reference the current element, and provide key for efficient updates when the list changes.
Column {
ForEach(items: @state.todos, key: "id") {
Row {
Checkbox {}
.checked(@item.completed)
.onChange(@actions.toggleTodo)
Text(@item.title)
.color("${item.completed ? '#9CA3AF' : '#111827'}")
}
.padding(8)
.gap(8)
}
}Arguments:
items: Array binding from state (e.g.,@state.todos)key(optional but recommended): Property name for stable identity (e.g.,"id")as(optional): Custom variable name (default is"item")
When — Pattern Matching
Match a value against multiple patterns and render the first matching branch.
When(value: @state.status) {
Case(match: "loading") {
Center { Spinner() }
}
Case(match: "error") {
Column {
Text("Something went wrong")
Button { Text("Retry") }
.onClick(@actions.reload)
}
}
Case(match: "success") {
ContentView()
}
Else {
Text("Unknown status")
}
}Match patterns support exact values ("loading"), multiple values ([200, 201, 204]), wildcards ("_"), and expressions ("${value >= 90}").
If — Boolean Conditionals
Show or hide UI sections based on a boolean condition.
If(condition: @state.isLoggedIn) {
Text("Welcome back, ${state.user.name}!")
Else {
Button { Text("Sign In") }
.onClick(@actions.signIn)
}
}For simple style changes, you don't need If — use expression bindings directly:
// No If needed — just change the color
Text(@state.status)
.color("${state.status == 'error' ? '#EF4444' : '#10B981'}")Comments
// Single line comment
/*
Multi-line
comment
*/
Column {
Text("Visible")
// Text("Hidden - commented out")
}Modules
Modules are components with state. Declare them with the module keyword.
module Counter {
Column {
Text("Count: ${state.count}")
Button { Text("+") }
.onClick(@actions.increment)
}
}The module name must match the TypeScript file that defines its state and actions.
Complete Example
module UserProfile {
Column {
// Header
Row {
Image(${state.user.avatar})
.size(64)
.borderRadius(32)
Column {
Text(${state.user.name})
.fontSize(20)
.fontWeight("bold")
Text("@${state.user.username}")
.color("#6B7280")
}
.gap(4)
}
.gap(16)
.padding(16)
Divider()
// Stats
Row {
Column {
Text("${state.user.posts}")
.fontWeight("bold")
Text("Posts")
.fontSize(12)
}
Column {
Text("${state.user.followers}")
.fontWeight("bold")
Text("Followers")
.fontSize(12)
}
Column {
Text("${state.user.following}")
.fontWeight("bold")
Text("Following")
.fontSize(12)
}
}
.horizontalAlignment("space-around")
.padding(16)
// Actions
Button {
Text(${state.isFollowing} ? "Unfollow" : "Follow")
}
.onClick(@actions.follow)
.backgroundColor(${state.isFollowing} ? "#E5E7EB" : "#3B82F6")
.padding(horizontal: 24, vertical: 12)
.borderRadius(8)
.fillMaxWidth(true)
.margin(16)
}
}Next Steps
- Control Flow — Deep dive into ForEach, When, If with complete examples
- Routing — Navigation and route guards
- Components — All built-in components
- Layout — Arranging components
- Styling — Complete applicator reference
- State & Modules — State management