Docs / Components / 01

NativeKitButton

A real platform button: Material 3 on Android and SwiftUI on iOS, with six variants, sizes, loading and Liquid Glass.

  • 6 variants
  • Liquid Glass
  • Loading state

Usage

A real platform button: Material 3 (Jetpack Compose) on Android and SwiftUI on iOS, driven from a single React Native API. You get native ripple, elevation and state layers on Android, and native press feedback, materials and Liquid Glass on iOS. It accepts all View props (style, testID, accessibilityLabel, …).

Usage.tsx
import { NativeKitButton } from '@nameisjayant/react-native-nativekit';

<NativeKitButton
  title="Continue"
  variant="filled"
  size="large"
  color="#2E7D32"
  loading={isSubmitting}
  onPress={submit}
/>

Variants

Six styles that map to each platform's native button family.

Variants
<NativeKitButton title="Filled"   variant="filled" />
<NativeKitButton title="Tonal"    variant="tonal" />
<NativeKitButton title="Outlined" variant="outlined" />
<NativeKitButton title="Text"     variant="text" />
<NativeKitButton title="Elevated" variant="elevated" />
<NativeKitButton title="Glass"    variant="glass" />
VariantAndroid (Compose M3)iOS (SwiftUI)
filled (default)Button.borderedProminent
tonalFilledTonalButton.bordered
outlinedOutlinedButton.borderless + stroked border
textTextButton.borderless
elevatedElevatedButton.borderedProminent + shadow
glassFilledTonalButton (fallback).glass / .glassProminent on iOS 26+, .ultraThinMaterial blur below

Sizes

Sizes
<NativeKitButton title="Small"  size="small" />
<NativeKitButton title="Medium" size="medium" />
<NativeKitButton title="Large"  size="large" />
SizeDefault heightAndroid padding / text styleiOS control size / font
small3612dp · labelMedium.small · .subheadline
medium (default)4424dp · labelLarge.regular · .body
large5232dp · titleMedium.large · .title3

Colors

color is the accent: the background for filled, tonal and elevated, the tint for glass, and the label + border color for outlined and text. textColor overrides the label (and spinner) color.

Colors
// Custom background
<NativeKitButton title="Confirm" color="#2E7D32" />

// Custom background + label
<NativeKitButton title="Warning" color="#FFE082" textColor="#4E342E" />

// Accent-colored outline
<NativeKitButton title="Delete" variant="outlined" color="#C62828" />

// Tinted glass
<NativeKitButton title="Explore" variant="glass" color="#6A1B9A" />

Any React Native ColorValue works: hex, rgb(), named colors, or PlatformColor.

Loading and disabled

loading shows a native spinner next to the title (CircularProgressIndicator on Android, ProgressView on iOS) and ignores presses while active.

Loading
const [submitting, setSubmitting] = useState(false);

const submit = async () => {
  setSubmitting(true);
  await api.placeOrder();
  setSubmitting(false);
};

<NativeKitButton
  title={submitting ? 'Placing order…' : 'Place order'}
  loading={submitting}
  onPress={submit}
/>

<NativeKitButton title="Unavailable" disabled />

Shape and typography

Shape
// Square corners
<NativeKitButton title="Square" cornerRadius={0} />

// Pill-ish rounded corners
<NativeKitButton title="Rounded" cornerRadius={24} />

// Custom font
<NativeKitButton title="Bold & big" fontSize={20} fontWeight="bold" />

fontWeight accepts 'default' | 'regular' | 'medium' | 'semibold' | 'bold'. Leave cornerRadius unset to keep the platform's default shape (fully rounded on Material 3, automatic on iOS).

Layout and sizing

Native views can't report an intrinsic size to Fabric, so NativeKitButton gives itself a sensible default frame: it stretches to its parent's width with a height based on size. Anything you pass in style wins.

Layout
// Fixed width, centered
<NativeKitButton
  title="Fixed width"
  style={{ width: 200, alignSelf: 'center' }}
/>

// Custom height
<NativeKitButton title="Tall" style={{ height: 64 }} />

// Side-by-side
<View style={{ flexDirection: 'row', gap: 12 }}>
  <NativeKitButton title="Cancel" variant="outlined" style={{ flex: 1 }} />
  <NativeKitButton title="Save" style={{ flex: 1 }} />
</View>

Liquid Glass (iOS 26+)

The glass variant adapts to what the device supports:

PlatformRendering
iOS 26+Apple's Liquid Glass: .glass, or .glassProminent when color is set
iOS < 26Frosted .ultraThinMaterial blur with an optional color tint and hairline border
AndroidFalls back to Material 3 FilledTonalButton
Glass
<ImageBackground source={hero} style={{ padding: 24 }}>
  <NativeKitButton title="Get started" variant="glass" size="large" />
  <NativeKitButton title="Tinted" variant="glass" color="#0A84FF" />
</ImageBackground>

Glass looks best over imagery or colorful content. Place it on top of a background to see the effect.

Full example

App.tsx
import { useState } from 'react';
import { ScrollView, StyleSheet, Text } from 'react-native';
import {
  NativeKitButton,
  type NativeKitButtonVariant,
} from '@nameisjayant/react-native-nativekit';

const VARIANTS: NativeKitButtonVariant[] = [
  'filled',
  'tonal',
  'outlined',
  'text',
  'elevated',
  'glass',
];

export default function App() {
  const [lastPressed, setLastPressed] = useState('none');
  const [loading, setLoading] = useState(false);

  const submit = () => {
    setLoading(true);
    setTimeout(() => setLoading(false), 2000);
  };

  return (
    <ScrollView contentContainerStyle={styles.container}>
      <Text>Last pressed: {lastPressed}</Text>

      {VARIANTS.map((variant) => (
        <NativeKitButton
          key={variant}
          title={variant}
          variant={variant}
          onPress={() => setLastPressed(variant)}
        />
      ))}

      <NativeKitButton
        title="Submit"
        size="large"
        color="#2E7D32"
        fontWeight="semibold"
        loading={loading}
        onPress={submit}
      />
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: { padding: 16, gap: 12 },
});

Props

PropTypeDefaultDescription
titlestring—Button label. Required.
variant'filled' | 'tonal' | 'outlined' | 'text' | 'elevated' | 'glass''filled'Visual style. See Variants.
size'small' | 'medium' | 'large''medium'Default height (36 / 44 / 52), padding and font.
colorColorValuethemeBackground for filled/tonal/elevated, tint for glass, label + border for outlined/text.
textColorColorValueper variantLabel and spinner color.
disabledbooleanfalseDisables the button and renders its disabled state.
loadingbooleanfalseShows a spinner next to the title and ignores presses.
cornerRadiusnumberplatformCorner radius in pt/dp.
fontSizenumberper sizeLabel font size in pt/sp.
fontWeight'default' | 'regular' | 'medium' | 'semibold' | 'bold''default'Label font weight.
onPress() => void—Called when the button is tapped.
...ViewPropsViewProps—style, testID, accessibilityLabel, etc.

All types are exported:

TypeScript
import type {
  NativeKitButtonProps,
  NativeKitButtonVariant,
  NativeKitButtonSize,
  NativeKitButtonFontWeight,
} from '@nameisjayant/react-native-nativekit';

Platform mapping

Android, Jetpack Compose (Material 3). Each button is rendered by a Compose ComposeView inside MaterialTheme. A trimmed look at what the filled variant renders:

NativeKitButton.kt
Button(
  onClick = { if (!state.loading) onPress() },
  modifier = Modifier.fillMaxSize(),
  enabled = !state.disabled,
  shape = if (state.cornerRadius >= 0f) RoundedCornerShape(state.cornerRadius.dp)
          else ButtonDefaults.shape,
  colors = ButtonDefaults.buttonColors(containerColor = accent, contentColor = content),
  contentPadding = PaddingValues(horizontal = 24.dp),
) {
  if (state.loading) {
    CircularProgressIndicator(Modifier.size(18.dp), color = LocalContentColor.current, strokeWidth = 2.dp)
    Spacer(Modifier.width(8.dp))
  }
  Text(state.title, style = MaterialTheme.typography.labelLarge, maxLines = 1)
}
  • Ripple, state layers and elevation come straight from Material 3.
  • Colors left unset fall back to the Material theme's color scheme.
  • glass has no Android equivalent and renders as FilledTonalButton.

iOS, SwiftUI. Each button is a SwiftUI Button hosted in a UIHostingController inside the Fabric component view. A trimmed look:

NativeKitButton.swift
Button(action: { if !model.loading { model.onPress?() } }) {
  HStack(spacing: 8) {
    if model.loading {
      ProgressView().tint(contentColor).controlSize(.small)
    }
    Text(model.title).font(font).lineLimit(1)
  }
  .frame(maxWidth: .infinity, maxHeight: .infinity)
}
.buttonStyle(.borderedProminent)   // varies by `variant`
.buttonBorderShape(borderShape)
.controlSize(controlSize)
.tint(accent)
.disabled(model.disabled)
  • Uses the system accent color when color is not set.
  • glass uses .glass / .glassProminent on iOS 26+ and a .ultraThinMaterial blur on older versions.