nori-ui

Button

Clickable action with variants, sizes, loading state, icon slots, and asChild.

3.6 kBgzipped

At a glance

  • Click target with full keyboard / RN Pressable semantics — focus ring on web, press feedback on native.
  • Forwards every Pressable prop (onPress, onLongPress, accessibilityLabel, …) untouched.
  • Use Toggle for two-state buttons and FloatButton for the floating-action-button pattern.

Preview

Direction:
Locale:

Native preview (Expo Snack)

variant

Visual emphasis. Pick by hierarchy, not color.

ValueUse for
primary (default)The single most-important action on a screen
secondaryEqually relevant actions, paired with a primary
ghostTertiary actions in dense layouts (cards, toolbars)
destructiveIrreversible actions — delete, leave, discard
<Button variant="primary">Save</Button>
<Button variant="destructive">Delete account</Button>

size

Density. md is the default and matches the rest of the form controls; sm for dense toolbars, lg for hero CTAs.

ValueMin heightPadding (horizontal)
sm32 px12 px
md (default)36 px16 px
lg44 px20 px
<Button size="lg">Get started</Button>

loading and disabled

loading swaps the leading icon (or label, in icon-only buttons) for a Spinner and disables interaction. The button keeps its width so the layout doesn't jump when the request returns. disabled greys the button out and blocks press handling without showing a spinner.

<Button loading>Saving…</Button>
<Button disabled>Save</Button>

Both forward aria-busy / aria-disabled so screen readers narrate the state correctly.

leadingIcon and trailingIcon

Two icon slots — pass any component matching { size?: number; color?: string }. Sized automatically to match the button's size. The Button renders nothing for an empty slot, so a text-only button stays text-only.

import { Save, ArrowRight } from 'lucide-react-native';
 
<Button leadingIcon={Save}>Save changes</Button>
<Button trailingIcon={ArrowRight}>Continue</Button>

In loading state the leadingIcon is replaced by a Spinner; the trailingIcon stays so the right-edge layout doesn't jump.

asChild

Renders the supplied child as the interactive root, so a Button can render as a Next.js <Link> (or any other element) while keeping all of its styles and accessibility behavior. Common for full-card clickable areas and routed actions.

import { Button } from '@nori-ui/core';
import Link from 'next/link';
 
<Button asChild variant="primary">
    <Link href="/billing">Manage billing</Link>
</Button>

Props

PropTypeDefaultDescription
asChildbooleanIf true, the single child becomes the interactive element (Slot pattern).
classNamestring
disabledboolean
leadingIconIconSlot
loadingboolean
refRef<View>
sizeenummd
trailingIconIconSlot
variantenumprimary

On this page

Preview theme