{"id":29152876,"url":"https://github.com/d-carrigg/slacknetblockbuilder","last_synced_at":"2026-05-04T23:32:30.764Z","repository":{"id":295015695,"uuid":"975891351","full_name":"d-carrigg/SlackNetBlockBuilder","owner":"d-carrigg","description":"A better way to create blocks for Slack Messages. Extends the SlackNet package.","archived":false,"fork":false,"pushed_at":"2025-06-11T03:36:24.000Z","size":952,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-01T01:04:17.019Z","etag":null,"topics":["dotnet","slack","slackapi"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/d-carrigg.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-01T05:08:31.000Z","updated_at":"2025-05-03T06:38:07.000Z","dependencies_parsed_at":"2025-05-26T06:47:07.111Z","dependency_job_id":null,"html_url":"https://github.com/d-carrigg/SlackNetBlockBuilder","commit_stats":null,"previous_names":["d-carrigg/slacknetblockbuilder"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/d-carrigg/SlackNetBlockBuilder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-carrigg%2FSlackNetBlockBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-carrigg%2FSlackNetBlockBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-carrigg%2FSlackNetBlockBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-carrigg%2FSlackNetBlockBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/d-carrigg","download_url":"https://codeload.github.com/d-carrigg/SlackNetBlockBuilder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-carrigg%2FSlackNetBlockBuilder/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262876917,"owners_count":23378140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","slack","slackapi"],"created_at":"2025-07-01T01:03:21.076Z","updated_at":"2026-05-04T23:32:30.759Z","avatar_url":"https://github.com/d-carrigg.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SlackNetBlockBuilder\n\nA fluent builder extension for [SlackNet](https://github.com/SlackNet/SlackNet) that simplifies creating Slack Block Kit\nUI elements with a clean, chainable API.\n\n*This project is not affiliated with Slack or SlackNet. I just needed a better way to create blocks for my Slack apps.*\n\n\u003e [!NOTE]\n\u003e This package is currently in beta. The code passes all tests, but breaking changes may occur until the v1 release.\n\n## Installation\n\n[![NuGet](https://img.shields.io/nuget/vpre/SlackNetBlockBuilder)](https://www.nuget.org/packages/SlackNetBlockBuilder/) [![Documentation](https://img.shields.io/badge/Documentation-GitHub%20Pages-blue)](https://d-carrigg.github.io/SlackNetBlockBuilder/)\n\nInstall the package via NuGet:\n\n```bash\ndotnet add package SlackNetBlockBuilder\n```\n\nVisual Studio\n\n```\nInstall-Package SlackNetBlockBuilder\n```\n\n## Getting Started\n\nHere are some examples to help you get started with SlackNetBlockBuilder:\n\n### Simple Message\n\n```csharp\nusing SlackNet;\nusing SlackNet.Blocks;\nusing SlackNet.WebApi;\n\n// Create a new block builder\nvar blocks = BlockBuilder.Create()\n    .AddSection(\"Hello, world!\")\n    .AddDivider()\n    .AddSection(section =\u003e section\n        .Text(\"This is a section with some formatted text\")\n        .Accessory(button =\u003e button\n            .Text(\"Click Me\")\n            .ActionId(\"button_click\")\n            .Primary()))\n    .Build();\n\n// Use with SlackNet to send a message\nawait slackApi.Chat.PostMessage(new Message\n{\n    Channel = channelId,\n    Blocks = blocks\n});\n```\n\n### Interactive Actions\n\n```csharp\nvar blocks = BlockBuilder.Create()\n    .AddSection(\"Please select an option:\")\n    .AddActions(actions =\u003e actions\n        .Button(button =\u003e button\n            .Text(\"Approve\")\n            .ActionId(\"approve_button\")\n            .Primary())\n        .Button(button =\u003e button\n            .Text(\"Reject\")\n            .ActionId(\"reject_button\")\n            .Danger())\n        .StaticSelect(select =\u003e select\n            .Placeholder(\"Choose an option\")\n            .ActionId(\"select_option\")\n            .AddOption(\"Option 1\", \"value1\")\n            .AddOption(\"Option 2\", \"value2\")\n            .AddOption(\"Option 3\", \"value3\")))\n    .Build();\n```\n\n### Forms with Input Elements\n\n```csharp\nvar blocks = BlockBuilder.Create()\n    .AddHeader(\"Submit Request Form\")\n    .AddInput\u003cPlainTextInput\u003e(\"Title\", input =\u003e input\n        .ActionId(\"title_input\")\n        .Placeholder(\"Enter a title\")\n        .Required())\n    .AddInput\u003cPlainTextInput\u003e(\"Description\", input =\u003e input\n        .ActionId(\"description_input\")\n        .Multiline()\n        .Placeholder(\"Enter a detailed description\")\n        .Optional())\n    .AddInput\u003cDatePicker\u003e(\"Due Date\", input =\u003e input\n        .ActionId(\"due_date_input\")\n        .Placeholder(\"Select a date\")\n        .Optional())\n    .AddActions(actions =\u003e actions\n        .Button(button =\u003e button\n            .Text(\"Submit\")\n            .ActionId(\"submit_form\")\n            .Primary())\n        .Button(button =\u003e button\n            .Text(\"Cancel\")\n            .ActionId(\"cancel_form\")))\n    .Build();\n```\n\n### Updating Messages\n\n```csharp\n// When handling an interaction payload\npublic async Task HandleInteraction(InteractionPayload payload)\n{\n    // Create a new block builder from the existing blocks\n    var updatedBlocks = BlockBuilder.From(payload.Message.Blocks)\n        // Remove a specific block by ID\n        .Remove(\"status_block\")\n        // Add a new status section\n        .AddSection(section =\u003e section\n            .BlockId(\"status_block\")\n            .Text(\"✅ Request approved!\"))\n        .Build();\n    \n    // Update the message\n    await slackApi.Chat.Update(new MessageUpdate\n    {\n        Channel = payload.Channel.Id,\n        Ts = payload.Message.Ts,\n        Blocks = updatedBlocks\n    });\n}\n```\n\n## Comparison with Traditional Approach\n\nThe following examples show how SlackNetBlockBuilder compares to the traditional approach of creating blocks manually.\n\n### Simple Message Creation\n\n#### With SlackNetBlockBuilder:\n\n```csharp\nusing SlackNet;\nusing SlackNet.Blocks;\nusing SlackNet.WebApi;\n\n// Create a new block builder\nvar blocks = BlockBuilder.Create()\n    .AddSection(\"Hello, world!\")\n    .AddDivider()\n    .AddSection(section =\u003e section\n        .Text(\"This is a section with some formatted text\")\n        .Accessory(button =\u003e button\n            .Text(\"Click Me\")\n            .ActionId(\"button_click\")\n            .Primary()))\n    .Build();\n\n// Use with SlackNet to send a message\nawait slackApi.Chat.PostMessage(new Message\n{\n    Channel = channelId,\n    Blocks = blocks\n});\n```\n\n#### Without SlackNetBlockBuilder (Traditional Approach):\n\nWith simple messages, the difference in terms of lines of code is negligible, but you will find that creating a\nmessage is easier and faster to type. Here is the same example as above without the BlockBuilder:\n\n```csharp\nusing SlackNet;\nusing SlackNet.WebApi;\nusing SlackNet.Blocks;\n\n// Create blocks manually\nvar blocks = new List\u003cBlock\u003e\n{\n    new SectionBlock\n    {\n        Text = new PlainText { Text = \"Hello, world!\" }\n    },\n    new DividerBlock(),\n    new SectionBlock\n    {\n        Text = new PlainText { Text = \"This is a section with some formatted text\" },\n        Accessory = new Button\n        {\n            Text = new PlainText { Text = \"Click Me\" },\n            ActionId = \"button_click\",\n            Style = ButtonStyle.Primary\n        }\n    }\n};\n\n// Use with SlackNet to send a message\nawait slackApi.Chat.PostMessage(new Message\n{\n    Channel = channelId,\n    Blocks = blocks\n});\n```\n\n### Interactive Actions\n\n#### With SlackNetBlockBuilder:\n\n```csharp\nvar blocks = BlockBuilder.Create()\n    .AddSection(\"Please select an option:\")\n    .AddActions(actions =\u003e actions\n        .Button(button =\u003e button\n            .Text(\"Approve\")\n            .ActionId(\"approve_button\")\n            .Primary())\n        .Button(button =\u003e button\n            .Text(\"Reject\")\n            .ActionId(\"reject_button\")\n            .Danger())\n        .StaticSelect(select =\u003e select\n            .Placeholder(\"Choose an option\")\n            .ActionId(\"select_option\")\n            .AddOption(\"Option 1\", \"value1\")\n            .AddOption(\"Option 2\", \"value2\")\n            .AddOption(\"Option 3\", \"value3\")))\n    .Build();\n```\n\n#### Without SlackNetBlockBuilder (Traditional Approach):\n\n```csharp\nvar blocks = new List\u003cBlock\u003e\n{\n    new SectionBlock\n    {\n        Text = new PlainText { Text = \"Please select an option:\" }\n    },\n    new ActionsBlock\n    {\n        Elements = new List\u003cIActionElement\u003e\n        {\n            new Button\n            {\n                Text = new PlainText { Text = \"Approve\" },\n                ActionId = \"approve_button\",\n                Style = ButtonStyle.Primary\n            },\n            new Button\n            {\n                Text = new PlainText { Text = \"Reject\" },\n                ActionId = \"reject_button\",\n                Style = ButtonStyle.Danger\n            },\n            new StaticSelectMenu\n            {\n                Placeholder = new PlainText { Text = \"Choose an option\" },\n                ActionId = \"select_option\",\n                Options = new List\u003cOption\u003e\n                {\n                    new Option\n                    {\n                        Text = new PlainText { Text = \"Option 1\" },\n                        Value = \"value1\"\n                    },\n                    new Option\n                    {\n                        Text = new PlainText { Text = \"Option 2\" },\n                        Value = \"value2\"\n                    },\n                    new Option\n                    {\n                        Text = new PlainText { Text = \"Option 3\" },\n                        Value = \"value3\"\n                    }\n                }\n            }\n        }\n    }\n};\n```\n\n### Forms with Input Elements\n\n#### With SlackNetBlockBuilder:\n\n```csharp\nvar blocks = BlockBuilder.Create()\n    .AddHeader(new PlainText(\"Submit Request Form\"))\n    .AddInput\u003cPlainTextInput\u003e(\"Title\", input =\u003e input\n        .ActionId(\"title_input\")\n        .Placeholder(\"Enter a title\")\n        .Required())\n    .AddInput\u003cPlainTextInput\u003e(\"Description\", input =\u003e input\n        .ActionId(\"description_input\")\n        .Multiline()\n        .Placeholder(\"Enter a detailed description\")\n        .Optional())\n    .AddInput\u003cDatePicker\u003e(\"Due Date\", input =\u003e input\n        .ActionId(\"due_date_input\")\n        .Placeholder(\"Select a date\")\n        .Optional())\n    .AddActions(actions =\u003e actions\n        .Button(button =\u003e button\n            .Text(\"Submit\")\n            .ActionId(\"submit_form\")\n            .Primary())\n        .Button(button =\u003e button\n            .Text(\"Cancel\")\n            .ActionId(\"cancel_form\")))\n    .Build();\n```\n\n#### Without SlackNetBlockBuilder (Traditional Approach):\n\n```csharp\nvar blocks = new List\u003cBlock\u003e\n{\n    new HeaderBlock\n    {\n        Text = new PlainText { Text = \"Submit Request Form\" }\n    },\n    new InputBlock\n    {\n        Label = new PlainText { Text = \"Title\" },\n        Element = new PlainTextInput\n        {\n            ActionId = \"title_input\",\n            Placeholder = new PlainText { Text = \"Enter a title\" }\n        },\n        Optional = false\n    },\n    new InputBlock\n    {\n        Label = new PlainText { Text = \"Description\" },\n        Element = new PlainTextInput\n        {\n            ActionId = \"description_input\",\n            Multiline = true,\n            Placeholder = new PlainText { Text = \"Enter a detailed description\" }\n        },\n        Optional = true\n    },\n    new InputBlock\n    {\n        Label = new PlainText { Text = \"Due Date\" },\n        Element = new DatePicker\n        {\n            ActionId = \"due_date_input\",\n            Placeholder = new PlainText { Text = \"Select a date\" }\n        },\n        Optional = true\n    },\n    new ActionsBlock\n    {\n        Elements = new List\u003cIActionElement\u003e\n        {\n            new Button\n            {\n                Text = new PlainText { Text = \"Submit\" },\n                ActionId = \"submit_form\",\n                Style = ButtonStyle.Primary\n            },\n            new Button\n            {\n                Text = new PlainText { Text = \"Cancel\" },\n                ActionId = \"cancel_form\"\n            }\n        }\n    }\n};\n```\n\n### Updating Messages\n\n#### With SlackNetBlockBuilder:\n\n```csharp\n// When handling an interaction payload\npublic async Task HandleInteraction(InteractionPayload payload)\n{\n    // Create a new block builder from the existing blocks\n    var updatedBlocks = BlockBuilder.From(payload.Message.Blocks)\n        // Remove a specific block by ID\n        .Remove(\"status_block\")\n        // Add a new status section\n        .AddSection(section =\u003e section\n            .BlockId(\"status_block\")\n            .Text(\"✅ Request approved!\"))\n        .Build();\n    \n    // Update the message\n    await slackApi.Chat.Update(new MessageUpdate\n    {\n        Channel = payload.Channel.Id,\n        Ts = payload.Message.Ts,\n        Blocks = updatedBlocks\n    });\n}\n```\n\n#### Without SlackNetBlockBuilder (Traditional Approach):\n\n```csharp\n// When handling an interaction payload\npublic async Task HandleInteraction(InteractionPayload payload)\n{\n    // Get the existing blocks\n    var existingBlocks = payload.Message.Blocks;\n    \n    // Create a new list of blocks\n    var updatedBlocks = new List\u003cBlock\u003e();\n    \n    // Copy all blocks except the status block\n    foreach (var block in existingBlocks)\n    {\n        if (block.BlockId != \"status_block\")\n        {\n            updatedBlocks.Add(block);\n        }\n    }\n    \n    // Add a new status section\n    updatedBlocks.Add(new SectionBlock\n    {\n        BlockId = \"status_block\",\n        Text = new PlainText { Text = \"✅ Request approved!\" }\n    });\n    \n    // Update the message\n    await slackApi.Chat.Update(new MessageUpdate\n    {\n        Channel = payload.Channel.Id,\n        Ts = payload.Message.Ts,\n        Blocks = updatedBlocks\n    });\n}\n```\n\n## Validation\n\nThe library includes validation to ensure that the blocks you create are valid according to Slack's Block Kit\nguidelines. This allows errors to be caught locally without requiring a network call. Right now, validation throws\nInvalidOperationException, but a future release may use a dedicated exception type for validation errors.\n\nExample:\n\n```csharp\nvar blocks = new BlockBuilder()\n    // throws InvalidOperationException\n    // Each field in a section block can have at most 3000 characters\n    .AddSection(\"A string with more than 3000 characters\") \n    .Build(); \n\n```\n\nConstraints on blocks are referenced from [Slack's Block Kit documentation](https://api.slack.com/reference/block-kit).\n\n## Further Examples\n\nFor more details see the documentation on [GitHub Pages](https://d-carrigg.github.io/SlackNetBlockBuilder/) or check out\nthe [examples](/examples)\ndirectory in the repository.\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-carrigg%2Fslacknetblockbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fd-carrigg%2Fslacknetblockbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-carrigg%2Fslacknetblockbuilder/lists"}