SkeleKit.iOS
0.1.4
dotnet add package SkeleKit.iOS --version 0.1.4
NuGet\Install-Package SkeleKit.iOS -Version 0.1.4
<PackageReference Include="SkeleKit.iOS" Version="0.1.4" />
<PackageVersion Include="SkeleKit.iOS" Version="0.1.4" />
<PackageReference Include="SkeleKit.iOS" />
paket add SkeleKit.iOS --version 0.1.4
#r "nuget: SkeleKit.iOS, 0.1.4"
#:package SkeleKit.iOS@0.1.4
#addin nuget:?package=SkeleKit.iOS&version=0.1.4
#tool nuget:?package=SkeleKit.iOS&version=0.1.4
SkeleKit is an early preview. It is usable for experimentation, but APIs may change before 1.0.
SkeleKit.iOS
A WPF-inspired UI library for .NET for iOS - no MAUI, no XAML. Native UIKit controls behind C# object-initializer syntax with AOT-safe MVVM bindings. App code never touches UIViewController, NSLayoutConstraint, or AppDelegate boilerplate.
- Native UIKit, 1:1: wraps the real UIKit controls. SkeleKit owns composition and layout, never rendering.
- Clean C# syntax:
Grid,StackPanel,Overlay,Border,Margin,Alignment, MVVM bindings and commands. Element trees via object initializers. - AOT-safe by construction: device builds are Mono full AOT + trimmed. No reflection, no expression trees, no runtime codegen. Bindings use compiled getters +
[CallerArgumentExpression]. - Framework concerns handled: dark mode, Dynamic Type, safe areas, keyboard avoidance.
- No base ViewModel required: works with plain
INotifyPropertyChanged/ICommand. CommunityToolkit.Mvvm fits naturally.
Requirements
- macOS with Xcode and the .NET 10 iOS workload
- .NET 10,
net10.0-ios, iOS 18+ - No dependencies beyond
Microsoft.Extensions.DependencyInjection
Quick start
dotnet new install SkeleKit.Templates
dotnet new skelekit-ios -n MyIosApp
cd MyIosApp
dotnet build -r iossimulator-arm64
The template creates the scene manifest, SkeleKit host, first [Page], launch screen, entitlements, and app-icon catalog. It references SkeleKit.iOS, which also carries the page source generator and the simulator hot-reload build targets.
<details>
<summary>Create project manually</summary>
Create the .NET project:
dotnet new ios -n MyIosAppTarget iOS 18 or later: set
<SupportedOSPlatformVersion>18.0</SupportedOSPlatformVersion>in the project file.Add SkeleKit:
dotnet add package SkeleKit.iOSUse SkeleKit's scene delegate: in
Info.plist, setUIApplicationSceneManifest→UISceneConfigurations→UIWindowSceneSessionRoleApplication→ item 0 →UISceneDelegateClassNametoSkeleWindowSceneDelegate. Delete the generatedAppDelegate.csandSceneDelegate.cs.Create the first page:
using SkeleKit; [Page] public class MainView : ContentView { public MainView() { Content = new Label() { Text = "Hello World!" }; } }Replace
Main.cswith the SkeleKit host:using SkeleKit; SkeleApplication.CreateBuilder() .SinglePage<MainView>() .Build() .Run(args);
</details>
Getting started
The following ViewModel uses the optional CommunityToolkit.Mvvm package; SkeleKit itself does not require a base ViewModel type.
// CounterView.cs
[Page]
public class CounterView : ContentView<CounterViewModel>
{
public CounterView(CounterViewModel viewModel) : base(viewModel)
{
Title = "Counter";
Content = new StackPanel
{
Spacing = 12,
Padding = new Thickness(16),
Children =
{
new Label
{
Text = Bind<int, string?>(vm => vm.Count, count => $"Tapped {count} times"),
FontSize = 34,
FontWeight = FontWeight.Bold
},
new Button
{
Text = "Click me",
Kind = ButtonStyle.Filled,
Command = viewModel.IncrementCommand
}
}
};
}
}
// CounterViewModel.cs
public partial class CounterViewModel : ObservableObject
{
[ObservableProperty]
public partial int Count { get; set; }
[RelayCommand]
void Increment() => Count++;
}
Styling
No ResourceDictionary and no setter system: shared values are plain statics, and a style is a typed action over the control: IntelliSense, compile-time checking, zero reflection.
static class Styles
{
public static readonly Style<Label> Caption = new(label =>
{
label.FontSize = 12;
label.TextColor = Colors.SecondaryLabel;
});
// BasedOn: Card runs first, then the overrides
public static readonly Style<Border> Card = new(border =>
{
border.Background = Colors.SecondaryGroupedBackground;
border.CornerRadius = 12;
});
public static readonly Style<Border> ProminentCard = new(Card, border =>
{
border.Shadow = new(opacity: 0.2, radius: 8, offsetY: 4);
});
}
new Label
{
Style = Styles.Caption, // explicit: Style goes FIRST, later lines win
Text = "Runtime"
};
// App-global themes, applied to every view of the type
SkeleApplication.CreateBuilder()
.UseTheme(theme => theme.Style(new Style<Button>(b => b.Kind = ButtonStyle.Tinted)));
Precedence (each source beats the previous): control defaults → theme (base type first) → explicit Style → the initializer after it.
What's in the box
- Layout:
Grid(star/auto/pixel, spans, spacing),StackPanel,Overlay,Border,ScrollView, per-viewIgnoresSafeArea. Two-pass measure/arrange engine, unit-testable off-device. - Controls:
Label,Button,Image(async, cached),TextField,SecureField,TextEditor,TextView(rich text + links),Switch,Slider,Stepper,ProgressBar,ActivityIndicator,Divider,Picker<T>,SegmentedControl,DatePicker,PageControl,ColorWell,MapView,WebView, andNativeViewas the UIKit escape hatch. - Lists: virtualized
CollectionView<T>overUICollectionView+ diffable data source — list (incl. inset-grouped), grid, carousel; sections + headers; pull-to-refresh, swipe actions, context menus, reorder, empty view, liveINotifyCollectionChangedupdates. - Bindings: one-way / two-way / one-way-to-source / one-time, converters, update triggers, nested paths,
BindingContextinheritance. Background-thread updates marshal to the UI thread. - Navigation: ViewModel-first
INavigator— push/pop, modals + sheets (detents), alert / confirm / action sheet. Shells viaTabs(...),Stack<T>(), orSinglePage<T>(); tab apps can opt into an iPad sidebar with.OnPad(pad => pad.Sidebar()). - Visual & animation:
Brush(solid / gradient / material),Shadow,CornerRadius;Animation+ an interruptible, scrubbableAnimator. - Styling: typed
Style<T>withBasedOn, an app-globalTheme,Label.TextStyle. - System integration: dark mode, Dynamic Type, VoiceOver, haptics, keyboard avoidance, gestures.
Repository layout
| Path | What |
|---|---|
Source/SkeleKit.slnx |
Main .NET solution |
Source/Framework/SkeleKit.iOS/ |
The library (multi-targets a net10.0 shim so the layout engine unit-tests without a simulator) |
Source/Framework/SkeleKit.Generators/ |
Source generators embedded in the SkeleKit.iOS package |
Source/Tests/SkeleKit.Tests/ |
xunit tests for the layout + binding engines |
Source/Samples/SkeleKit.Gallery/ |
Gallery app: every control and layout, MVVM end to end |
Source/Samples/SkeleKit.Template/ |
Minimal app that is also the source for dotnet new skelekit-ios |
Source/Packaging/ |
NuGet template-pack project |
Tools/ |
Developer tooling, including the Rider plugin |
Docs/ |
Architecture, API sketch, ADRs |
Assets/ |
Brand and design source assets |
Escape hatches
UIKit is never required, but always reachable: wrap any UIView with NativeView, reach the native control via view.Native, the hosting controller via ContentView.Controller, or attach a UIGestureRecognizer with view.AddGesture(...).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-ios26.0 is compatible. |
-
net10.0-ios26.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Improve API XML documentation across the framework.