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
Text("Hello")
Text(text: "Hello")
// 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 conditionals and iteration.
ForEach
Iterates over a collection and renders children for each item. Use @item to reference each item.
Column {
ForEach(items: @state.todos) {
Row {
Text(@item.title)
Text(@item.status)
}
}
}Arguments:
items: The collection to iterate overkey(optional): Property to use as unique key for efficient updates
When
Pattern matching on a value with multiple cases.
When(value: @state.status) {
Case(match: "loading") {
Spinner()
}
Case(match: "error") {
Text("Something went wrong")
}
Case(match: "success") {
Text("Done!")
}
Else {
Text("Unknown status")
}
}Match Patterns:
- Exact values:
Case(match: "loading") - Multiple values:
Case(match: [200, 201, 204]) - Wildcards:
Case(match: "_")orCase(match: "*") - Expressions:
Case(match: "${value >= 1 && value <= 100}")
If
Boolean conditional for simple true/false branching.
If(condition: @state.isLoggedIn) {
Text("Welcome back!")
Else {
Text("Please sign in")
}
}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
- Components - All built-in components
- Layout - Arranging components
- Styling - Complete applicator reference
- State & Modules - State management