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

Import

component.ts
import { NeuNumberInputComponent } from '@neural-ui/native/number-input';

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.

Make room for a new idea

Adjust the seat count for a studio workshop and compare the live total before saving a local reservation. Changing the quantity afterwards preserves the saved summary. No booking or payment is sent.

View and copy the complete example
basic.component.ts
import { Component, signal } from '@angular/core';
import { NeuButtonComponent } from '@neural-ui/native/button';
import { NeuDividerComponent } from '@neural-ui/native/divider';
import { NeuAvatarComponent } from '@neural-ui/native/avatar';
import { NeuNumberInputComponent } from '@neural-ui/native/number-input';
import { View, Text, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuButtonComponent, NeuDividerComponent, NeuAvatarComponent, NeuNumberInputComponent, View, Text, ScrollView],
  template: `
    <scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="false"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">Make room for a new idea</text><text class="product-caption">Neural Studio · Creative workshops</text></view>
    <view class="workshop-ticket"><view class="product-row"><view class="workshop-date"><text class="workshop-day">06</text><text class="workshop-month">NOVEMBER</text></view><view class="product-copy"><text class="workshop-kicker">STUDIO SESSION / 03</text><text class="workshop-title">Shape & motion</text><text class="workshop-caption">Friday · 10:00–12:00</text></view></view>
    <view class="workshop-host"><neu-avatar label="Alex Morgan" size="sm" /><view class="product-copy"><text class="workshop-caption">A hands-on workshop with Alex Morgan</text></view></view></view>
    <view class="product-surface"><neu-number-input label="Seats for your team" decreaseLabel="Remove one seat" increaseLabel="Add one seat" [(value)]="guests" [min]="1" [max]="10" [step]="1" />
    <text class="product-caption">€24 per seat · Materials included · Up to 10</text><neu-divider />
    <view class="product-row"><view class="product-copy"><text class="product-caption">Workshop total</text><text class="product-heading">{{ guests() }} {{ guests() === 1 ? 'seat' : 'seats' }}</text></view><text class="workshop-total">{{ guests() * 24 }} €</text></view>
    <neu-button label="Reserve locally" (pressed)="reserved.set(guests())" />
    @if (reserved()) { <text class="product-caption" accessibilityLiveRegion="polite">Saved on this screen: {{ reserved() }} {{ reserved() === 1 ? 'seat' : 'seats' }} · {{ reserved() * 24 }} €</text> }</view></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); }
.workshop-ticket { gap: 18px; padding: 20px; border-radius: 18px; background-color: #f5eadf; }
.workshop-date { width: 68px; gap: 3px; align-items: center; }
.workshop-day { color: #6b4733; font-size: 36px; line-height: 40px; font-weight: 600; }
.workshop-month { color: #795c47; font-size: 9px; line-height: 14px; font-weight: 600; letter-spacing: 0.5px; }
.workshop-kicker { color: #795c47; font-size: 9px; line-height: 14px; font-weight: 600; letter-spacing: 0.5px; }
.workshop-title { color: #372a23; font-size: 22px; line-height: 28px; font-weight: 600; }
.workshop-caption { color: #6b5548; font-size: 12px; line-height: 18px; }
.workshop-host { flex-direction: row; gap: 10px; align-items: center; padding-top: 14px; border-top-width: 1px; border-color: #dccbbb; }
.workshop-total { color: var(--neu-text, #172033); font-size: 30px; line-height: 36px; font-weight: 600; }
  `,
})
export class ExampleComponent {
  readonly guests = signal(2);
  readonly reserved = signal(0);
}

Different increments and read-only totals

Adjust a donation in steps of five; the read-only field mirrors the chosen amount.

View and copy the complete example
different-increments-and-read-only-totals.component.ts
import { Component, signal } from '@angular/core';
import { NeuNumberInputComponent } from '@neural-ui/native/number-input';
import { View, ScrollView } from '@ng-native/components';

@Component({
  selector: 'app-example',
  imports: [NeuNumberInputComponent, View, ScrollView],
  template: `
    <scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
    <neu-number-input label="Donation amount" [(value)]="donation" [min]="0" [max]="100" [step]="5" />
    <neu-number-input label="Donation preview" [value]="donation()" [readonly]="true" />
    </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 {
  readonly donation = signal(10);
}
Interactive playground

Change the settings and try the result.

Device captures shown in English.

Number Input · android · native capture
AndroidNative screenshot
Number Input · ios · native capture
iOSNative screenshot

API reference

Inputs

NameTypeDefaultBindingDescription
labelstringRequiredInputHuman-readable name for the control, action or group.
minnumber0InputLowest accepted user value. The default is zero, so negative values are rejected unless you explicitly configure a negative minimum.
maxnumber100InputUpper bound of the range or item limit, according to this control.
stepnumber1InputPositive increment used by the increase/decrease buttons and numeric editing. Defaults to 1; configure a positive decimal such as 0.5 when needed.
disabledbooleanfalseInputDisables user interaction. Values can still be supplied by the application.
readonlybooleanfalseInputPrevents user editing or selection while retaining the current value.
decreaseLabelstring'Decrease'InputText or accessible name used for decrease. It does not perform the action by itself.
increaseLabelstring'Increase'InputText or accessible name used for increase. It does not perform the action by itself.

Models

NameTypeDefaultBindingDescription
valuenumber0Model · two-wayNumeric value; edits and step actions apply min, max and step. While typing, the field keeps temporary blanks, signs and decimal separators without restoring the previous digit. Blur or a step action normalizes the displayed text; an external value replacement discards the draft.

Outputs

NamePayloadWhen it emits
valueChangenumberEmits the updated value value. [(value)] binds this output together with its model input.
touchvoidReports user interaction to the surrounding form or application.

Model state

Bind the signal with [(modelName)] without calling it. Use modelName() to read its value.

model-fields.ts
import { signal } from '@angular/core';

// Fields inside your component class
readonly value = signal<number>(0);