# First Widgets ## Getting Started Start by importing the singleton [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html) instance. :::code-group ```ts [app.ts] import { App } from "astal/gtk3" App.start({ main() { // you will instantiate Widgets here // and setup anything else if you need } }) ``` ::: After your [bundle step](./installation.md) run `gjs -m app.js`, and that's it! Now you have an Astal instance running written in TypeScript. ## Root of every shell component: Window Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. A widget can be as small as a button or an entire bar. The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which will hold all widgets. ::: code-group ```tsx [widget/Bar.tsx] function Bar(monitor = 0) { return Content of the widget } ``` ::: ::: code-group ```ts [app.ts] import Bar from "./widget/Bar" App.start({ main() { Bar(0) Bar(1) // instantiate for each monitor }, }) ``` ::: ## Creating and nesting widgets Widgets are JavaScript functions which return Gtk widgets, either by using JSX or using a widget constructor. :::code-group ```tsx [MyButton.tsx] function MyButton(): JSX.Element { return } ``` ```ts [MyButton.ts (gtk3)] import { Widget } from "astal/gtk3" function MyButton(): Widget.Button { return new Widget.Button( { onClicked: "echo hello" }, new Widget.Label({ label: "Click me!" }), ) } ``` ```ts [MyButton.ts (gtk4)] import { Widget } from "astal/gtk4" function MyButton(): Widget.Button { return Widget.Button( { onClicked: "echo hello" }, Widget.Label({ label: "Click me!" }), ) } ``` ::: :::info The only difference between the two is the return type. Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), while using constructors the return type is the actual type of the widget. It is rare to need the actual return type, so most if not all of the time, you can use markup. ::: Now that you have declared `MyButton`, you can nest it into another component. ```tsx function MyBar() { return Click The button } ``` Notice that widgets you defined start with a capital letter ``. Lowercase tags are builtin widgets, while capital letter is for custom widgets. ## Displaying Data JSX lets you put markup into JavaScript. Curly braces let you “escape back” into JavaScript so that you can embed some variable from your code and display it. ```tsx function MyWidget() { const label = "hello" return } ``` You can also pass JavaScript to markup attributes ```tsx function MyWidget() { const label = "hello" return } ``` :::info Bindings have an `.as()` method which lets you transform the assigned value. In the case of a Label, its label property expects a string, so it needs to be turned to a string first. ::: :::tip `Variables` have a shorthand for `bind(variable).as(transform)` ```tsx const v = Variable(0) const transform = (v) => v.toString() return {/* these two are equivalent */} ``` ::: Here is an example of a battery percent label that binds the `percentage` property of the Battery object from the [Battery Library](/guide/libraries/battery): ```tsx import Battery from "gi://AstalBattery" import { bind } from "astal" function BatteryPercentage() { const bat = Battery.get_default() return