Getting started
Install @sinequa/galactik, wire up its design tokens, and render a first form that opens a confirmation dialog.
Four steps take you from an empty Angular 22 workspace to a form built entirely from @sinequa/galactik
components, styled by its design tokens.
Prerequisites
An Angular 22 workspace with Tailwind CSS v4 already set up. @sinequa/galactik declares three peer
dependencies — install them alongside it:
Prop
Type
Install
npm install @sinequa/galactik @angular/aria cnConfigure the design tokens
Concept — galactik tokens
Every component reads its colors, spacing and radii exclusively from CSS custom properties —
--bg-primary-base, --font-primary-muted, --radius-2xl — never a raw Tailwind color or a shadcn utility
class. @sinequa/galactik ships no CSS of its own: an application declares these tokens itself, once.
Import Tailwind, then a stylesheet that declares the tokens under :root. This repository's own demo app
keeps that stylesheet at projects/demo/src/css/galactik-tokens.css — copy it (or your design system's own
export of the same token set) into your application and import it right after Tailwind:
@import "tailwindcss";
@import "./galactik-tokens.css";Every galactik component now renders with the correct look — there is nothing to configure per component.
A dark variant is optional: the demo app keeps its dark-mode token overrides in a second file
(galactik-tokens-dark.css), scoped under a .dark class, imported after the light one.
Render a first component
A small form: an Input bound to a signal, and a Button that opens a confirmation Dialog before
"submitting" — the same createCallable/injectCallRef pattern the Dialog page
teaches in full.
import { afterNextRender, Component, viewChild } from "@angular/core";
import {
ButtonComponent,
createCallable,
DialogBodyComponent,
DialogComponent,
DialogContentComponent,
DialogDescriptionComponent,
DialogFooterComponent,
DialogHeaderComponent,
DialogTitleComponent,
injectCallRef,
} from "@sinequa/galactik";
@Component({
selector: "confirm-save-dialog",
imports: [
DialogComponent,
DialogContentComponent,
DialogHeaderComponent,
DialogTitleComponent,
DialogBodyComponent,
DialogDescriptionComponent,
DialogFooterComponent,
ButtonComponent,
],
template: `
<dialog #dialog="dialog" (closed)="call.end($event === 'dialog-confirm')">
<DialogContent size="sm">
<DialogHeader>
<DialogTitle>Save changes?</DialogTitle>
</DialogHeader>
<DialogBody>
<DialogDescription>Save "{{ call.props().name }}" as the new name?</DialogDescription>
</DialogBody>
<DialogFooter>
<button variant="secondary" size="md" (click)="dialog.close('dialog-cancel')">Cancel</button>
<button variant="primary" size="md" (click)="dialog.close('dialog-confirm')">Save</button>
</DialogFooter>
</DialogContent>
</dialog>
`,
})
export class ConfirmSaveDialog {
protected readonly call = injectCallRef<{ name: string }, boolean>();
private readonly dialog = viewChild.required(DialogComponent);
constructor() {
afterNextRender(() => this.dialog().showModal());
}
}
export const ConfirmSave = createCallable<{ name: string }, boolean>(ConfirmSaveDialog);import { Component, signal } from "@angular/core";
import { ButtonComponent, InputComponent, InputControlDirective } from "@sinequa/galactik";
import { ConfirmSave } from "./confirm-save-dialog";
@Component({
selector: "name-form",
imports: [InputComponent, InputControlDirective, ButtonComponent],
template: `
<div class="flex items-end gap-2">
<input-group>
<input
input-control
type="text"
placeholder="Your name"
[value]="name()"
(input)="name.set($any($event.target).value)"
/>
</input-group>
<button variant="primary" size="md" [disabled]="!name().trim()" (click)="save()">Save</button>
</div>
@if (saved()) {
<p>Saved as "{{ saved() }}".</p>
}
`,
})
export class NameFormComponent {
protected readonly name = signal("");
protected readonly saved = signal("");
protected async save() {
const confirmed = await ConfirmSave.call({ name: this.name() });
if (confirmed) this.saved.set(this.name());
}
}provideCallable() must be registered once in your application's providers for ConfirmSave.call(...) to
work without passing an explicit injector — see the Dialog page's Options
section.