Skip to main content
Neural Nativev0.1.0-beta.1Documentation

Import

component.ts
import { NeuButtonComponent } from '@neural-ui/native/button';

Examples

Import ExampleComponent into its parent and place <app-example /> inside your application’s root neu-theme. The preview supplies the device frame and safe areas; use the root setup from Installation in your app.

Project actions

Edit a project name, preview the draft and save your changes. The primary action is available only when there is something to save.

View and copy the complete example
project-editor.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { NeuInputComponent } from '@neural-ui/native/input';
import { NeuBadgeComponent } from '@neural-ui/native/badge';
import { NeuModalComponent } from '@neural-ui/native/modal';
import { View, Text, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, NeuInputComponent, NeuBadgeComponent, NeuModalComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="true"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">Make it yours</text><text class="product-caption">Product workspace</text></view>
    <view class="product-surface"><neu-input label="Project name" [(value)]="name" placeholder="Name your project" />
    <text class="product-caption">A clear name helps your team find the right work.</text>
    <view class="product-actions"><neu-button label="Save changes" size="sm" [disabled]="!name().trim() || name().trim() === savedName()" (pressed)="savedName.set(name().trim())" /><neu-button label="Preview" size="sm" variant="text" (pressed)="preview.set(true)" /></view>
    <text class="product-caption" accessibilityLiveRegion="polite">{{ name().trim() === savedName() ? 'All changes saved' : 'Unsaved changes' }}</text></view>
    <neu-modal title="Project preview" [(open)]="preview"><view class="product-section"><neu-badge label="Draft" tone="neutral" /><text class="product-heading">{{ name().trim() || 'Untitled project' }}</text><text>Invite your team and plan the first milestone.</text></view></neu-modal></view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

:host { flex: 1; flex-shrink: 1; min-height: 0; }
.product-scroll { flex: 1; flex-shrink: 1; height: 0px; min-height: 0; }
.product-stack { gap: 24px; padding-bottom: 20px; }
.product-section { gap: 12px; }
.product-row { flex-direction: row; align-items: center; gap: 12px; }
.product-copy { flex: 1; min-width: 0; gap: 4px; }
.product-title { color: var(--neu-text, #172033); font-size: 24px; line-height: 30px; font-weight: 600; }
.product-heading { color: var(--neu-text, #172033); font-size: 17px; line-height: 23px; font-weight: 600; }
.product-caption { color: var(--neu-muted, #596477); font-size: 14px; line-height: 20px; }
.product-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
.product-surface { gap: 16px; padding: 16px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); border-width: 1px; border-color: var(--neu-border, #a5afbf); }

  `,
})
export class ExampleComponent {
  readonly name = signal('Mobile launch');
  readonly savedName = signal('Mobile launch');
  readonly preview = signal(false);
}

Variants

Compare four visual treatments and press any action to update the count.

View and copy the complete example
variants.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { View, Text, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <view class="usage-buttons">
    <neu-button label="Save changes" variant="solid" (pressed)="saved.set(saved() + 1)" />
    <neu-button label="Preview" variant="tonal" (pressed)="saved.set(saved() + 1)" />
    <neu-button label="Cancel" variant="outline" (pressed)="saved.set(saved() + 1)" />
    <neu-button label="Learn more" variant="text" (pressed)="saved.set(saved() + 1)" />
    </view><text class="usage-caption">Actions: {{ saved() }}</text>
    </view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }

.usage-buttons { gap: 12px; align-items: flex-start; }
  `,
})
export class ExampleComponent {
  readonly saved = signal(0);
}

Semantic colors

Compare the six semantic colors supplied by the theme.

View and copy the complete example
semantic-colors.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { View, Text, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <view class="usage-buttons">@for (tone of tones; track tone) {
    <neu-button [label]="tone" [tone]="tone" (pressed)="saved.set(saved() + 1)" />
    }</view><text class="usage-caption">Actions: {{ saved() }}</text>
    </view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }

.usage-buttons { gap: 12px; align-items: flex-start; }
  `,
})
export class ExampleComponent {
  readonly saved = signal(0);
  readonly tones = ['brand', 'neutral', 'success', 'info', 'warning', 'danger'] as const;
}

Sizes

Compare sm, md and lg with the same label.

View and copy the complete example
sizes.component.ts
import { Component } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { View, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, View, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <view class="usage-buttons"><neu-button label="Continue" size="sm" /><neu-button label="Continue" size="md" /><neu-button label="Continue" size="lg" /></view>
    </view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }

.usage-buttons { gap: 16px; align-items: flex-start; }
  `,
})
export class ExampleComponent {

}

Loading and disabled

Start or stop the saving state and compare it with an unavailable action.

View and copy the complete example
loading-and-disabled.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { View, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, View, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <view class="usage-buttons"><neu-button label="Saving changes" [loading]="saving()" /><neu-button label="Unavailable action" [disabled]="true" /><neu-button label="Toggle loading" variant="text" (pressed)="saving.set(!saving())" /></view>
    </view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }

.usage-buttons { gap: 12px; align-items: flex-start; }
  `,
})
export class ExampleComponent {
  readonly saving = signal(true);
}

Full width

Let the primary action fill its available container width.

View and copy the complete example
full-width.component.ts
import { Component } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { View, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, View, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <neu-button label="Continue" [fullWidth]="true" /><neu-button label="Cancel" variant="text" />
    </view></scroll-view>
  `,
  styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }

.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }


  `,
})
export class ExampleComponent {

}
Interactive playground

Change the settings and try the result.

Device captures shown in English.

Button · android · native capture
AndroidNative screenshot
Button · ios · native capture
iOSNative screenshot

API reference

Inputs

NameTypeDefaultBindingDescription
labelstringRequiredInputHuman-readable name for the control, action or group.
accessibilityLabelstring''InputAccessible action name. When empty, Button uses its visible label.
variantNeuVariant'solid'InputVisual hierarchy: solid, tonal, outline or text. Colors come from the surrounding theme.
toneNeuTone'brand'InputSemantic color: neutral, brand, success, info, warning or danger. The accent value remains a compatible alias for brand. Colors use NeuTheme tokens; explain statuses with words as well as color.
sizeNeuSize'md'InputThe sm, md and lg sizes have minimum heights of 48, 56 and 64 points and label sizes of 14, 16 and 18 points. Larger text can increase height. Use fullWidth to fill the parent width.
fullWidthbooleanfalseInputFill the available width of the parent container. The false setting restores the natural content width; size still controls height and typography.
disabledbooleanfalseInputDisables user interaction. Values can still be supplied by the application.
loadingbooleanfalseInputShows the native loading indicator and prevents Button or IconButton activation.

Models

This component declares no two-way models.

Outputs

NamePayloadWhen it emits
pressedTouchEventEmits the native press event when an enabled action is activated.

Types and data interfaces

Use the imports in your application. The definitions below are provided for reference.

NeuVariant

NeuVariant.ts
import type { NeuVariant } from '@neural-ui/native/foundation';

// Public definition for reference only. Import this type; do not redeclare it.
export type NeuVariant = 'solid' | 'tonal' | 'outline' | 'text';

NeuTone

NeuTone.ts
import type { NeuTone } from '@neural-ui/native/foundation';

// Public definition for reference only. Import this type; do not redeclare it.
export type NeuTone = 'neutral' | 'brand' | 'accent' | 'success' | 'info' | 'warning' | 'danger';

NeuSize

NeuSize.ts
import type { NeuSize } from '@neural-ui/native/foundation';

// Public definition for reference only. Import this type; do not redeclare it.
export type NeuSize = 'sm' | 'md' | 'lg';

TouchEvent

TouchEvent.ts
import type { TouchEvent } from '@ng-native/components';
import type { NativeSyntheticEvent } from '@ng-native/fabric';
import type { TouchEventPayload } from '@ng-native/components';

// Public definition for reference only. Import this type; do not redeclare it.
export type TouchEvent = NativeSyntheticEvent<TouchEventPayload>;

NativeSyntheticEvent

NativeSyntheticEvent.ts
import type { NativeSyntheticEvent } from '@ng-native/fabric';

// Public definition for reference only. Import this type; do not redeclare it.
export interface NativeSyntheticEvent<T = unknown> {
    readonly nativeEvent: T;
    /**
     * The node the event happened on, which a listener further up can compare with its own: RN's
     * `event.target`. Null where a host has no node to name.
     */
    readonly target?: unknown;
    stopPropagation(): void;
    isPropagationStopped(): boolean;
}

TouchEventPayload

TouchEventPayload.ts
import type { TouchEventPayload } from '@ng-native/components';
import type { TouchPayload } from '@ng-native/fabric';

// Public definition for reference only. Import this type; do not redeclare it.
export interface TouchEventPayload extends TouchPayload {
    readonly touches?: readonly TouchPayload[];
    readonly changedTouches?: readonly TouchPayload[];
}

TouchPayload

TouchPayload.ts
import type { TouchPayload } from '@ng-native/fabric';

// Public definition for reference only. Import this type; do not redeclare it.
export interface TouchPayload {
    readonly pageX?: number;
    readonly pageY?: number;
    readonly locationX?: number;
    readonly locationY?: number;
    readonly identifier?: number;
    readonly target?: number;
    readonly timestamp?: number;
}