Components

Button

Button is a press target with a text label. It is filled with a theme color, darkens while pressed and reports presses with onPress. It looks the same on iOS and Android.

ui-button.tsx Edit in Playground Open in new tab
// Button: the four variants, a disabled button and press counting.
import { mount, signal, Text, View } from "nsh";
import { Button } from "nsh/ui/mobile";

function App() {
  const presses = signal(0);
  const enabled = signal(true);
  const press = () => presses.set(presses() + 1);
  return (
    <View style={{ flex: 1, backgroundColor: "#ffffff", padding: 16, paddingTop: 24, gap: 12 }}>
      <Text style={{ fontSize: 22, fontWeight: "700" }}>Button</Text>
      <Text style={{ color: "#737373" }}>{`Pressed ${presses()} times`}</Text>
      <Button title="Primary" onPress={press} />
      <Button title="Secondary" variant="secondary" onPress={press} />
      <Button title="Danger" variant="danger" onPress={press} />
      <Button title="Plain" variant="plain" onPress={press} />
      <Button title={enabled() ? "Enabled" : "Disabled"} disabled={!enabled()} onPress={press} />
      <View style={{ flexDirection: "row", gap: 12 }}>
        <Button class="flex-1" title="Reset" variant="secondary" onPress={() => presses.set(0)} />
        <Button
          class="flex-1"
          title={enabled() ? "Disable" : "Enable"}
          variant="plain"
          onPress={() => enabled.set(!enabled())}
        />
      </View>
      <Button title="Custom corners" class="rounded-full" accessibilityLabel="A button with round ends" onPress={press} />
    </View>
  );
}

mount(App);
import { Button } from "nsh/ui/mobile";

#Usage

import { mount, signal, Text, View } from "nsh";
import { Button } from "nsh/ui/mobile";

function App() {
  const count = signal(0);
  return (
    <View style={{ flex: 1, padding: 16, gap: 12, justifyContent: "center" }}>
      <Text>{`Pressed ${count()} times`}</Text>
      <Button title="Press me" onPress={() => count.set(count() + 1)} />
    </View>
  );
}

mount(App);

The button lays its label out in a row, centered, with 16 pt of horizontal and 12 pt of vertical padding. In a column it stretches to the column’s width, like any view. Pass class or style to size or round it differently:

<View style={{ flexDirection: "row", gap: 8 }}>
  <Button class="flex-1" title="Cancel" variant="secondary" onPress={cancel} />
  <Button class="flex-1" title="Save" onPress={save} />
</View>

#Variants

<Button title="Save" />                         {/* primary (default) */}
<Button title="Not now" variant="secondary" />
<Button title="Delete" variant="danger" />
<Button title="Learn more" variant="plain" />
VariantBackgroundPressedLabel
primary (default)primary.backgroundprimary.active.backgroundprimary.foreground
secondarysecondary.backgroundsecondary.active.backgroundsecondary.foreground
dangerdanger.backgrounddanger.active.backgrounddanger.foreground
plaintransparentaccent.backgroundforeground

Use danger for destructive actions and plain for low-emphasis actions such as a card footer’s secondary action.

#Disabled

<Button title="Submit" disabled={!valid()} onPress={submit} />

A disabled button is shown at 50% opacity, does not respond to presses and shows no press feedback.

#Props

PropTypeDefaultDescription
titlestringrequiredThe label.
variant"primary" | "secondary" | "danger" | "plain""primary"The look (see Variants).
disabledbooleanfalseNo presses, no feedback, 50% opacity.
accessibilityLabelstring | nulltitleWhat screen readers read, when title is not enough.
class, classList, style, testID, onLayout, refApplied to the button’s root view. class and style override the button’s own styles.

#Events

EventPayloadWhen
onPressnoneThe button was pressed (released inside it). Not sent while disabled.

#Theming

The label uses the theme’s font.size (16 pt by default) with a semibold weight. The corners use radius (12 pt by default). The colors come from the theme keys in the variants table. See Theming.

#Accessibility

The button has the button role. Screen readers read accessibilityLabel if you set it, otherwise title. While disabled, the button is reported as disabled.